jwt_lab/
sign.rs

1use crate::{types::{Algorithm, Header, Claims}, jwk::Key, Error, Result};
2
3/// Convert our Algorithm enum to jsonwebtoken's Algorithm enum
4fn to_jalg(a: Algorithm) -> jsonwebtoken::Algorithm {
5    use Algorithm::*;
6    match a {
7        HS256 => jsonwebtoken::Algorithm::HS256,
8        HS384 => jsonwebtoken::Algorithm::HS384,
9        HS512 => jsonwebtoken::Algorithm::HS512,
10        RS256 => jsonwebtoken::Algorithm::RS256,
11        RS384 => jsonwebtoken::Algorithm::RS384,
12        RS512 => jsonwebtoken::Algorithm::RS512,
13        ES256 => jsonwebtoken::Algorithm::ES256,
14        ES384 => jsonwebtoken::Algorithm::ES384,
15        ES512 => jsonwebtoken::Algorithm::ES384,
16        EdDSA => jsonwebtoken::Algorithm::EdDSA,
17    }
18}
19
20/// Sign a JWT token with the given header, claims, and key
21///
22/// # Arguments
23///
24/// * `header` - The JWT header containing algorithm and optional fields
25/// * `claims` - The JWT claims (payload) to sign
26/// * `key` - The signing key (must match the algorithm in the header)
27///
28/// # Returns
29///
30/// Returns a `Result` containing the signed JWT token or an error
31///
32/// # Errors
33///
34/// - `Error::DisabledAlg` if the algorithm is not enabled via feature flags
35/// - `Error::Key` if the key is invalid or doesn't match the algorithm
36/// - `Error::Internal` if signing fails
37pub fn sign(header: &Header, claims: &Claims, key: &Key) -> Result<String> {
38    use jsonwebtoken::{Header as JHeader, EncodingKey, encode};
39
40    match header.alg {
41        Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => { #[cfg(not(feature="hs"))] return Err(Error::DisabledAlg("HS")); }
42        Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => { #[cfg(not(feature="rs"))] return Err(Error::DisabledAlg("RS")); }
43        Algorithm::ES256 | Algorithm::ES384 | Algorithm::ES512 => { #[cfg(not(feature="es"))] return Err(Error::DisabledAlg("ES")); }
44        Algorithm::EdDSA => { #[cfg(not(feature="eddsa"))] return Err(Error::DisabledAlg("EdDSA")); }
45    }
46
47    let mut h = JHeader::new(to_jalg(header.alg));
48    h.typ = Some(header.typ.clone().unwrap_or_else(|| "JWT".into()));
49    h.kid = header.kid.clone();
50
51    let enc = match key {
52        Key::Hs(shared) => EncodingKey::from_secret(shared),
53        Key::RsaPrivatePem(pem) => EncodingKey::from_rsa_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
54        Key::EcPrivatePem(pem) => EncodingKey::from_ec_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
55        Key::EdPrivatePem(pem) => EncodingKey::from_ed_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
56        _ => return Err(Error::Key("private key required to sign".into())),
57    };
58
59    encode(&h, &claims.0, &enc).map_err(|e| Error::Internal(e.to_string()))
60}
61
62impl crate::types::Jwt {
63    /// Sign this JWT with the given key
64    ///
65    /// # Arguments
66    ///
67    /// * `key` - The signing key (must match the algorithm in the header)
68    ///
69    /// # Returns
70    ///
71    /// Returns a `Result` containing the signed JWT token or an error
72    ///
73    /// # Errors
74    ///
75    /// - `Error::DisabledAlg` if the algorithm is not enabled via feature flags
76    /// - `Error::Key` if the key is invalid or doesn't match the algorithm
77    /// - `Error::Internal` if signing fails
78    pub fn sign(&self, key: &Key) -> Result<String> {
79        sign(&self.header, &self.claims, key)
80    }
81}