small_jwt 1.1.0

Simple and small JWT libary
Documentation
//! JWT header struct and Algorithm enum.

// TODO: comment what is header, algorithm, type;
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Header {
    pub alg: Algorithm,
    pub typ: String,
}

impl Default for Header {
    /// Return HS256 Jwt token.
    fn default() -> Self {
        Self {
            alg: Algorithm::HS256,
            typ: String::from("JWT"),
        }
    }
}

impl Header {
    pub fn new(alg: Algorithm) -> Self {
        Self {
            alg,
            typ: String::from("JWT"),
        }
    }
}

/// Invariant limiter, repsonsible for signing.
#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Algorithm {
    /// HMACSHA256
    HS256,
}

impl Algorithm {
    /// Returns signing function based on enum variant.
    pub fn sign_fn(&self) -> impl Fn(&[u8], &[u8]) -> crate::error::Result<Vec<u8>> {
        match self {
            Self::HS256 => Self::sign_hs256,
        }
    }

    fn sign_hs256(data: &[u8], key: &[u8]) -> crate::error::Result<Vec<u8>> {
        use hmac::Mac;
        
        let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key)
            .map_err(crate::error::Error::from)?;

        mac.update(data);

        Ok(mac.finalize().into_bytes().to_vec())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_header_is_jwt_and_hs256() {
        let header = Header::default();

        assert_eq!(header.alg, Algorithm::HS256);
        assert_eq!(header.typ, "JWT");
    }

    // INFO:
    //  - For HS256 tests: https://www.devglan.com/online-tools/hmac-sha256-online
    
    const SECRET_KEY: &[u8] = b"super_secret_key";
    const MESSAGE: &[u8] = b"I love Kvanik";

    #[test]
    fn hs256_success() {
        let hashed = Algorithm::HS256.sign_fn()(MESSAGE, SECRET_KEY);

        assert!(hashed.is_ok(), "Should be ok");
        assert_eq!(b"65f66e9a84e26aaebcf5189d9986ea32f800dbe1f328d3436bf305707c802799", hex::encode(hashed.unwrap()).as_bytes());
    }
}