jwt-lab 0.1.1

JWT crate for Rust: decode, verify, sign, mutate, JWK/JWKS, algorithm selection, time validation, and secure APIs.
Documentation
use crate::{types::{Algorithm, Header, Claims}, jwk::Key, Error, Result};

/// Convert our Algorithm enum to jsonwebtoken's Algorithm enum
fn to_jalg(a: Algorithm) -> jsonwebtoken::Algorithm {
    use Algorithm::*;
    match a {
        HS256 => jsonwebtoken::Algorithm::HS256,
        HS384 => jsonwebtoken::Algorithm::HS384,
        HS512 => jsonwebtoken::Algorithm::HS512,
        RS256 => jsonwebtoken::Algorithm::RS256,
        RS384 => jsonwebtoken::Algorithm::RS384,
        RS512 => jsonwebtoken::Algorithm::RS512,
        ES256 => jsonwebtoken::Algorithm::ES256,
        ES384 => jsonwebtoken::Algorithm::ES384,
        ES512 => jsonwebtoken::Algorithm::ES384,
        EdDSA => jsonwebtoken::Algorithm::EdDSA,
    }
}

/// Sign a JWT token with the given header, claims, and key
///
/// # Arguments
///
/// * `header` - The JWT header containing algorithm and optional fields
/// * `claims` - The JWT claims (payload) to sign
/// * `key` - The signing key (must match the algorithm in the header)
///
/// # Returns
///
/// Returns a `Result` containing the signed JWT token or an error
///
/// # Errors
///
/// - `Error::DisabledAlg` if the algorithm is not enabled via feature flags
/// - `Error::Key` if the key is invalid or doesn't match the algorithm
/// - `Error::Internal` if signing fails
pub fn sign(header: &Header, claims: &Claims, key: &Key) -> Result<String> {
    use jsonwebtoken::{Header as JHeader, EncodingKey, encode};

    match header.alg {
        Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => { #[cfg(not(feature="hs"))] return Err(Error::DisabledAlg("HS")); }
        Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => { #[cfg(not(feature="rs"))] return Err(Error::DisabledAlg("RS")); }
        Algorithm::ES256 | Algorithm::ES384 | Algorithm::ES512 => { #[cfg(not(feature="es"))] return Err(Error::DisabledAlg("ES")); }
        Algorithm::EdDSA => { #[cfg(not(feature="eddsa"))] return Err(Error::DisabledAlg("EdDSA")); }
    }

    let mut h = JHeader::new(to_jalg(header.alg));
    h.typ = Some(header.typ.clone().unwrap_or_else(|| "JWT".into()));
    h.kid = header.kid.clone();

    let enc = match key {
        Key::Hs(shared) => EncodingKey::from_secret(shared),
        Key::RsaPrivatePem(pem) => EncodingKey::from_rsa_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
        Key::EcPrivatePem(pem) => EncodingKey::from_ec_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
        Key::EdPrivatePem(pem) => EncodingKey::from_ed_pem(pem).map_err(|e| Error::Key(e.to_string()))?,
        _ => return Err(Error::Key("private key required to sign".into())),
    };

    encode(&h, &claims.0, &enc).map_err(|e| Error::Internal(e.to_string()))
}

impl crate::types::Jwt {
    /// Sign this JWT with the given key
    ///
    /// # Arguments
    ///
    /// * `key` - The signing key (must match the algorithm in the header)
    ///
    /// # Returns
    ///
    /// Returns a `Result` containing the signed JWT token or an error
    ///
    /// # Errors
    ///
    /// - `Error::DisabledAlg` if the algorithm is not enabled via feature flags
    /// - `Error::Key` if the key is invalid or doesn't match the algorithm
    /// - `Error::Internal` if signing fails
    pub fn sign(&self, key: &Key) -> Result<String> {
        sign(&self.header, &self.claims, key)
    }
}