Skip to main content

karbon_framework/security/
jwt.rs

1use chrono::Utc;
2use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
3use serde::{Deserialize, Serialize};
4
5/// JWT claims stored in the token
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Claims {
8    /// User ID
9    pub sub: String,
10    /// Username
11    pub username: String,
12    /// User roles
13    pub roles: Vec<String>,
14    /// Expiration timestamp
15    pub exp: i64,
16    /// Issued at
17    pub iat: i64,
18}
19
20/// JWT token manager
21#[derive(Clone)]
22pub struct JwtManager {
23    encoding_key: EncodingKey,
24    decoding_key: DecodingKey,
25    expiration: i64,
26}
27
28impl JwtManager {
29    /// Create a new JWT manager with the given secret and expiration (in seconds)
30    pub fn new(secret: &str, expiration: i64) -> Self {
31        Self {
32            encoding_key: EncodingKey::from_secret(secret.as_bytes()),
33            decoding_key: DecodingKey::from_secret(secret.as_bytes()),
34            expiration,
35        }
36    }
37
38    /// Generate a JWT token for a user
39    pub fn generate(&self, user_id: &str, username: &str, roles: Vec<String>) -> Result<String, jsonwebtoken::errors::Error> {
40        let now = Utc::now().timestamp();
41        let claims = Claims {
42            sub: user_id.to_string(),
43            username: username.to_string(),
44            roles,
45            exp: now + self.expiration,
46            iat: now,
47        };
48
49        encode(&Header::default(), &claims, &self.encoding_key)
50    }
51
52    /// Validate and decode a JWT token
53    pub fn verify(&self, token: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
54        let token_data = decode::<Claims>(token, &self.decoding_key, &Validation::default())?;
55        Ok(token_data.claims)
56    }
57
58    /// Generate an opaque refresh token (random 48-byte string, NOT a JWT).
59    /// The caller must hash it with `Crypto::hash_token()` before storing in DB.
60    /// Returns the raw token to send to the client.
61    pub fn generate_refresh_token() -> String {
62        super::Crypto::random_token(48)
63    }
64}