auth_framework/security/
secure_jwt.rs1use crate::errors::Result;
2use jsonwebtoken::{Algorithm, DecodingKey};
3use serde::{Deserialize, Serialize};
4use std::collections::HashSet;
5use std::time::Duration;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct SecureJwtClaims {
9 pub sub: String,
10 pub iss: String,
11 pub aud: String,
12 pub exp: i64,
13 pub nbf: i64,
14 pub iat: i64,
15 pub jti: String,
16 pub scope: String,
17 pub typ: String,
18 pub sid: Option<String>,
19 pub client_id: Option<String>,
20 pub auth_ctx_hash: Option<String>,
21}
22
23#[derive(Debug, Clone)]
24pub struct SecureJwtConfig {
25 pub allowed_algorithms: Vec<Algorithm>,
26 pub required_issuers: HashSet<String>,
27 pub required_audiences: HashSet<String>,
28 pub max_token_lifetime: Duration,
29 pub clock_skew: Duration,
30 pub require_jti: bool,
31 pub validate_nbf: bool,
32 pub allowed_token_types: HashSet<String>,
33 pub require_secure_transport: bool,
34 pub jwt_secret: String,
36}
37
38impl Default for SecureJwtConfig {
39 fn default() -> Self {
40 let mut allowed_token_types = HashSet::new();
41 allowed_token_types.insert("access".to_string());
42 allowed_token_types.insert("refresh".to_string());
43 allowed_token_types.insert("JARM".to_string());
44
45 let mut required_issuers = HashSet::new();
46 required_issuers.insert("auth-framework".to_string());
47
48 Self {
49 allowed_algorithms: vec![Algorithm::HS256, Algorithm::RS256, Algorithm::ES256],
50 required_issuers,
51 required_audiences: HashSet::new(),
52 max_token_lifetime: Duration::from_secs(3600),
53 clock_skew: Duration::from_secs(30),
54 require_jti: true,
55 validate_nbf: true,
56 allowed_token_types,
57 require_secure_transport: false,
58 jwt_secret: "CHANGE_THIS_IN_PRODUCTION_USE_PROPER_KEY_MANAGEMENT".to_string(),
59 }
60 }
61}
62
63#[derive(Debug)]
64pub struct SecureJwtValidator {
65 config: SecureJwtConfig,
66 revoked_tokens: std::sync::Mutex<std::collections::HashSet<String>>,
67}
68
69impl SecureJwtValidator {
70 pub fn new(config: SecureJwtConfig) -> Self {
71 Self {
72 config,
73 revoked_tokens: std::sync::Mutex::new(std::collections::HashSet::new()),
74 }
75 }
76
77 pub fn get_decoding_key(&self) -> jsonwebtoken::DecodingKey {
79 jsonwebtoken::DecodingKey::from_secret(self.config.jwt_secret.as_bytes())
80 }
81
82 pub fn validate_token(
83 &self,
84 token: &str,
85 decoding_key: &DecodingKey,
86 verify_signature: bool,
87 ) -> Result<SecureJwtClaims> {
88 use jsonwebtoken::{Algorithm, Validation, decode};
89
90 let mut validation = Validation::new(Algorithm::HS256);
92 validation.validate_exp = false; validation.validate_aud = false; validation.validate_nbf = false; if !verify_signature {
97 validation.insecure_disable_signature_validation();
98 }
99
100 match decode::<SecureJwtClaims>(token, decoding_key, &validation) {
102 Ok(token_data) => {
103 let claims = token_data.claims;
104
105 if self.is_token_revoked(&claims.jti)? {
107 return Err(crate::errors::AuthError::Unauthorized(
108 "Token is revoked".to_string(),
109 ));
110 }
111
112 Ok(claims)
115 }
116 Err(e) => Err(crate::errors::AuthError::Unauthorized(format!(
117 "JWT validation failed: {}",
118 e
119 ))),
120 }
121 }
122
123 pub fn is_token_revoked(&self, jti: &str) -> Result<bool> {
124 let revoked_tokens = self.revoked_tokens.lock().unwrap();
125 Ok(revoked_tokens.contains(jti))
126 }
127
128 pub fn revoke_token(&self, jti: &str) -> Result<()> {
129 let mut revoked_tokens = self.revoked_tokens.lock().unwrap();
130 revoked_tokens.insert(jti.to_string());
131 Ok(())
132 }
133
134 pub fn cleanup_revoked_tokens(&self, _expired_cutoff: std::time::SystemTime) -> Result<()> {
135 Ok(())
138 }
139}
140
141