Coverage Report

Created: 2026-03-31 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jsonwebtoken-10.3.0/src/encoding.rs
Line
Count
Source
1
use std::fmt::{Debug, Formatter};
2
3
use base64::{
4
    Engine,
5
    engine::general_purpose::{STANDARD, URL_SAFE},
6
};
7
use serde::ser::Serialize;
8
9
use crate::algorithms::AlgorithmFamily;
10
use crate::crypto::CryptoProvider;
11
use crate::errors::{ErrorKind, Result, new_error};
12
use crate::header::Header;
13
#[cfg(feature = "use_pem")]
14
use crate::pem::decoder::PemEncodedKey;
15
use crate::serialization::{b64_encode, b64_encode_part};
16
17
/// A key to encode a JWT with. Can be a secret, a PEM-encoded key or a DER-encoded key.
18
/// This key can be re-used so make sure you only initialize it once if you can for better performance.
19
#[derive(Clone)]
20
pub struct EncodingKey {
21
    family: AlgorithmFamily,
22
    content: Vec<u8>,
23
}
24
25
impl EncodingKey {
26
    /// The algorithm family this key is for.
27
0
    pub fn family(&self) -> AlgorithmFamily {
28
0
        self.family
29
0
    }
30
31
    /// If you're using a HMAC secret that is not base64, use that.
32
0
    pub fn from_secret(secret: &[u8]) -> Self {
33
0
        EncodingKey { family: AlgorithmFamily::Hmac, content: secret.to_vec() }
34
0
    }
35
36
    /// If you have a base64 HMAC secret, use that.
37
0
    pub fn from_base64_secret(secret: &str) -> Result<Self> {
38
0
        let out = STANDARD.decode(secret)?;
39
0
        Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: out })
40
0
    }
41
42
    /// For loading websafe base64 HMAC secrets, ex: ACME EAB credentials.
43
0
    pub fn from_urlsafe_base64_secret(secret: &str) -> Result<Self> {
44
0
        let out = URL_SAFE.decode(secret)?;
45
0
        Ok(EncodingKey { family: AlgorithmFamily::Hmac, content: out })
46
0
    }
47
48
    /// If you are loading a RSA key from a .pem file.
49
    /// This errors if the key is not a valid RSA key.
50
    /// Only exists if the feature `use_pem` is enabled.
51
    ///
52
    /// # NOTE
53
    ///
54
    /// According to the [ring doc](https://docs.rs/ring/latest/ring/signature/struct.RsaKeyPair.html#method.from_pkcs8),
55
    /// the key should be at least 2047 bits.
56
    ///
57
    #[cfg(feature = "use_pem")]
58
0
    pub fn from_rsa_pem(key: &[u8]) -> Result<Self> {
59
0
        let pem_key = PemEncodedKey::new(key)?;
60
0
        let content = pem_key.as_rsa_key()?;
61
0
        Ok(EncodingKey { family: AlgorithmFamily::Rsa, content: content.to_vec() })
62
0
    }
63
64
    /// If you are loading a ECDSA key from a .pem file
65
    /// This errors if the key is not a valid private EC key
66
    /// Only exists if the feature `use_pem` is enabled.
67
    ///
68
    /// # NOTE
69
    ///
70
    /// The key should be in PKCS#8 form.
71
    ///
72
    /// You can generate a key with the following:
73
    ///
74
    /// ```sh
75
    /// openssl ecparam -genkey -noout -name prime256v1 \
76
    ///     | openssl pkcs8 -topk8 -nocrypt -out ec-private.pem
77
    /// ```
78
    #[cfg(feature = "use_pem")]
79
0
    pub fn from_ec_pem(key: &[u8]) -> Result<Self> {
80
0
        let pem_key = PemEncodedKey::new(key)?;
81
0
        let content = pem_key.as_ec_private_key()?;
82
0
        Ok(EncodingKey { family: AlgorithmFamily::Ec, content: content.to_vec() })
83
0
    }
84
85
    /// If you are loading a EdDSA key from a .pem file
86
    /// This errors if the key is not a valid private Ed key
87
    /// Only exists if the feature `use_pem` is enabled.
88
    #[cfg(feature = "use_pem")]
89
0
    pub fn from_ed_pem(key: &[u8]) -> Result<Self> {
90
0
        let pem_key = PemEncodedKey::new(key)?;
91
0
        let content = pem_key.as_ed_private_key()?;
92
0
        Ok(EncodingKey { family: AlgorithmFamily::Ed, content: content.to_vec() })
93
0
    }
94
95
    /// If you know what you're doing and have the DER-encoded key, for RSA only
96
0
    pub fn from_rsa_der(der: &[u8]) -> Self {
97
0
        EncodingKey { family: AlgorithmFamily::Rsa, content: der.to_vec() }
98
0
    }
99
100
    /// If you know what you're doing and have the DER-encoded key, for ECDSA
101
0
    pub fn from_ec_der(der: &[u8]) -> Self {
102
0
        EncodingKey { family: AlgorithmFamily::Ec, content: der.to_vec() }
103
0
    }
104
105
    /// If you know what you're doing and have the DER-encoded key, for EdDSA
106
0
    pub fn from_ed_der(der: &[u8]) -> Self {
107
0
        EncodingKey { family: AlgorithmFamily::Ed, content: der.to_vec() }
108
0
    }
109
110
    /// Get the value of the key.
111
0
    pub fn inner(&self) -> &[u8] {
112
0
        &self.content
113
0
    }
114
115
    /// Try to get the HMAC secret from a key.
116
0
    pub fn try_get_hmac_secret(&self) -> Result<&[u8]> {
117
0
        if self.family == AlgorithmFamily::Hmac {
118
0
            Ok(self.inner())
119
        } else {
120
0
            Err(new_error(ErrorKind::InvalidKeyFormat))
121
        }
122
0
    }
123
}
124
125
impl Debug for EncodingKey {
126
0
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
127
0
        f.debug_struct("EncodingKey")
128
0
            .field("family", &self.family)
129
0
            .field("content", &"[redacted]")
130
0
            .finish()
131
0
    }
132
}
133
134
/// Encode the header and claims given and sign the payload using the algorithm from the header and the key.
135
/// If the algorithm given is RSA or EC, the key needs to be in the PEM format.
136
///
137
/// ```rust
138
/// use serde::{Deserialize, Serialize};
139
/// use jsonwebtoken::{encode, Algorithm, Header, EncodingKey};
140
///
141
/// #[derive(Debug, Serialize, Deserialize)]
142
/// struct Claims {
143
///    sub: String,
144
///    company: String
145
/// }
146
///
147
/// let my_claims = Claims {
148
///     sub: "b@b.com".to_owned(),
149
///     company: "ACME".to_owned()
150
/// };
151
///
152
/// // my_claims is a struct that implements Serialize
153
/// // This will create a JWT using HS256 as algorithm
154
/// let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret("secret".as_ref())).unwrap();
155
/// ```
156
0
pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &EncodingKey) -> Result<String> {
157
0
    if key.family != header.alg.family() {
158
0
        return Err(new_error(ErrorKind::InvalidAlgorithm));
159
0
    }
160
161
0
    let signing_provider = (CryptoProvider::get_default().signer_factory)(&header.alg, key)?;
162
163
0
    if signing_provider.algorithm() != header.alg {
164
0
        return Err(new_error(ErrorKind::InvalidAlgorithm));
165
0
    }
166
167
0
    let encoded_header = b64_encode_part(&header)?;
168
0
    let encoded_claims = b64_encode_part(claims)?;
169
0
    let message = [encoded_header, encoded_claims].join(".");
170
171
0
    let signature = b64_encode(signing_provider.try_sign(message.as_bytes())?);
172
173
0
    Ok([message, signature].join("."))
174
0
}
Unexecuted instantiation: jsonwebtoken::encoding::encode::<surrealdb_core::iam::token::Claims>
Unexecuted instantiation: jsonwebtoken::encoding::encode::<_>