a06673b
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode};
use uuid::Uuid;
use crate::claims::{AccessClaims, RefreshClaims};
use crate::error::JwtError;
pub fn algorithm_from_str(s: &str) -> Result<jsonwebtoken::Algorithm, JwtError> {
match s {
"EdDSA" | "ed25519" | "Ed25519" => Ok(jsonwebtoken::Algorithm::EdDSA),
"ES256" => Ok(jsonwebtoken::Algorithm::ES256),
"RS256" => Ok(jsonwebtoken::Algorithm::RS256),
other => Err(JwtError::Config(format!("unsupported algorithm: {other}"))),
}
}
pub fn encode_access_token(
claims: &AccessClaims,
key: &EncodingKey,
alg: jsonwebtoken::Algorithm,
) -> Result<String, JwtError> {
let mut header = Header::new(alg);
header.kid = Some(claims.kid.clone());
encode(&header, claims, key).map_err(JwtError::from)
}
pub fn encode_refresh_token(
claims: &RefreshClaims,
key: &EncodingKey,
alg: jsonwebtoken::Algorithm,
) -> Result<String, JwtError> {
let mut header = Header::new(alg);
header.kid = Some(claims.kid.clone());
encode(&header, claims, key).map_err(JwtError::from)
}
pub fn decode_access_token(
token: &str,
key: &DecodingKey,
alg: jsonwebtoken::Algorithm,
issuer: &str,
audience: &str,
clock_skew_seconds: i64,
) -> Result<AccessClaims, JwtError> {
let mut validation = Validation::new(alg);
validation.set_issuer(&[issuer.to_string()]);
validation.set_audience(&[audience.to_string()]);
validation.leeway = clock_skew_seconds as u64;
validation.validate_exp = true;
let data = decode::<AccessClaims>(token, key, &validation)?;
Ok(data.claims)
}
pub fn decode_refresh_token(
token: &str,
key: &DecodingKey,
alg: jsonwebtoken::Algorithm,
issuer: &str,
audience: &str,
clock_skew_seconds: i64,
) -> Result<RefreshClaims, JwtError> {
let mut validation = Validation::new(alg);
validation.set_issuer(&[issuer.to_string()]);
validation.set_audience(&[audience.to_string()]);
validation.leeway = clock_skew_seconds as u64;
validation.validate_exp = true;
let data = decode::<RefreshClaims>(token, key, &validation)?;
Ok(data.claims)
}
pub fn kid_from_token(token: &str) -> Option<String> {
// Best-effort: decode only the header, ignore signature.
let header = jsonwebtoken::decode_header(token).ok()?;
header.kid
}
pub fn extract_kid(token: &str) -> Option<Uuid> {
kid_from_token(token).and_then(|k| Uuid::parse_str(&k).ok())
}