Skip to main content

auth_framework/tokens/
mod.rs

1//! Token management and validation for the authentication framework.
2use crate::errors::{AuthError, Result, TokenError};
3use crate::providers::{OAuthProvider, ProfileExtractor, ProviderProfile};
4use base64::Engine as _;
5use chrono::{DateTime, Utc};
6use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, encode};
7use rsa::pkcs1::DecodeRsaPublicKey;
8use rsa::pkcs8::DecodePublicKey;
9use rsa::traits::PublicKeyParts;
10use serde::{Deserialize, Serialize};
11use sha2::{Digest, Sha256};
12#[cfg(feature = "postgres-storage")]
13use sqlx::FromRow;
14use std::collections::HashMap;
15use std::time::Duration;
16use uuid::Uuid;
17
18/// An issued authentication token with all associated metadata.
19///
20/// Created by [`TokenManager`] and returned from
21/// [`AuthFramework::authenticate`](crate::auth::AuthFramework::authenticate).
22/// Contains the encoded `access_token` string, optional `refresh_token`,
23/// granted scopes, and contextual [`TokenMetadata`].
24#[cfg_attr(feature = "postgres-storage", derive(FromRow))]
25#[derive(Clone, Serialize, Deserialize)]
26pub struct AuthToken {
27    /// Unique token identifier
28    pub token_id: String,
29
30    /// User identifier this token belongs to
31    pub user_id: String,
32
33    /// Access token value
34    pub access_token: String,
35
36    /// Token type (e.g., "bearer")
37    pub token_type: Option<String>,
38
39    /// Subject claim
40    pub subject: Option<String>,
41
42    /// Token issuer
43    pub issuer: Option<String>,
44
45    /// Optional refresh token
46    pub refresh_token: Option<String>,
47
48    /// When the token was issued
49    pub issued_at: DateTime<Utc>,
50
51    /// When the token expires
52    pub expires_at: DateTime<Utc>,
53
54    /// Scopes granted to this token
55    pub scopes: crate::types::Scopes,
56
57    /// Authentication method used to obtain this token
58    pub auth_method: String,
59
60    /// Client ID that requested this token
61    pub client_id: Option<String>,
62
63    /// User profile data (optional)
64    pub user_profile: Option<ProviderProfile>,
65
66    /// User's permissions
67    pub permissions: crate::types::Permissions,
68
69    /// User's roles
70    pub roles: crate::types::Roles,
71
72    /// Additional token metadata
73    pub metadata: TokenMetadata,
74}
75
76impl std::fmt::Debug for AuthToken {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        f.debug_struct("AuthToken")
79            .field("token_id", &self.token_id)
80            .field("user_id", &self.user_id)
81            .field("access_token", &"[REDACTED]")
82            .field("token_type", &self.token_type)
83            .field("subject", &self.subject)
84            .field("issuer", &self.issuer)
85            .field(
86                "refresh_token",
87                if self.refresh_token.is_some() {
88                    &"Some([REDACTED])"
89                } else {
90                    &"None"
91                },
92            )
93            .field("issued_at", &self.issued_at)
94            .field("expires_at", &self.expires_at)
95            .field("scopes", &self.scopes)
96            .field("auth_method", &self.auth_method)
97            .field("client_id", &self.client_id)
98            .field("permissions", &self.permissions)
99            .field("roles", &self.roles)
100            .field("metadata", &self.metadata)
101            .finish()
102    }
103}
104
105/// Builder for creating `AuthToken` instances with fluent API.
106///
107/// Reduces cognitive load when constructing tokens with many optional fields.
108/// Required fields are set in `new()`, optional fields via builder methods.
109///
110/// # Example
111///
112/// ```rust
113/// use auth_framework::tokens::{AuthToken, TokenMetadata};
114/// use auth_framework::types::{Scopes, Permissions, Roles};
115/// use chrono::{Utc, Duration};
116///
117/// let token = AuthToken::builder("user123", "token456", "access_token_here")
118///     .scopes(Scopes::new(vec!["read".to_string(), "write".to_string()]))
119///     .permissions(Permissions::new(vec!["admin".to_string()]))
120///     .roles(Roles::new(vec!["user".to_string()]))
121///     .expires_at(Utc::now() + Duration::hours(1))
122///     .client_id("client123")
123///     .build();
124/// ```
125#[derive(Debug, Clone)]
126pub struct AuthTokenBuilder {
127    token_id: String,
128    user_id: String,
129    access_token: String,
130    token_type: Option<String>,
131    subject: Option<String>,
132    issuer: Option<String>,
133    refresh_token: Option<String>,
134    issued_at: DateTime<Utc>,
135    expires_at: DateTime<Utc>,
136    scopes: crate::types::Scopes,
137    auth_method: String,
138    client_id: Option<String>,
139    user_profile: Option<ProviderProfile>,
140    permissions: crate::types::Permissions,
141    roles: crate::types::Roles,
142    metadata: TokenMetadata,
143}
144
145impl AuthTokenBuilder {
146    /// Create a new builder with required fields.
147    ///
148    /// Sets sensible defaults for optional fields:
149    /// - `issued_at`: current time
150    /// - `expires_at`: 1 hour from now
151    /// - `scopes`, `permissions`, `roles`: empty collections
152    /// - `auth_method`: "unknown"
153    /// - `metadata`: default (empty)
154    pub fn new(
155        token_id: impl Into<String>,
156        user_id: impl Into<String>,
157        access_token: impl Into<String>,
158    ) -> Self {
159        let now = Utc::now();
160        Self {
161            token_id: token_id.into(),
162            user_id: user_id.into(),
163            access_token: access_token.into(),
164            token_type: None,
165            subject: None,
166            issuer: None,
167            refresh_token: None,
168            issued_at: now,
169            expires_at: now + chrono::Duration::hours(1),
170            scopes: crate::types::Scopes::empty(),
171            auth_method: "unknown".to_string(),
172            client_id: None,
173            user_profile: None,
174            permissions: crate::types::Permissions::empty(),
175            roles: crate::types::Roles::empty(),
176            metadata: TokenMetadata::default(),
177        }
178    }
179
180    /// Set the token type (e.g., "bearer").
181    ///
182    /// # Example
183    ///
184    /// ```rust
185    /// use auth_framework::tokens::AuthToken;
186    ///
187    /// let token = AuthToken::builder("t1", "u1", "access")
188    ///     .token_type("bearer")
189    ///     .build();
190    /// assert_eq!(token.token_type.as_deref(), Some("bearer"));
191    /// ```
192    pub fn token_type(mut self, token_type: impl Into<String>) -> Self {
193        self.token_type = Some(token_type.into());
194        self
195    }
196
197    /// Set the subject claim.
198    ///
199    /// # Example
200    ///
201    /// ```rust
202    /// use auth_framework::tokens::AuthToken;
203    ///
204    /// let token = AuthToken::builder("t1", "u1", "access")
205    ///     .subject("user@example.com")
206    ///     .build();
207    /// assert_eq!(token.subject.as_deref(), Some("user@example.com"));
208    /// ```
209    pub fn subject(mut self, subject: impl Into<String>) -> Self {
210        self.subject = Some(subject.into());
211        self
212    }
213
214    /// Set the token issuer.
215    ///
216    /// # Example
217    ///
218    /// ```rust
219    /// use auth_framework::tokens::AuthToken;
220    ///
221    /// let token = AuthToken::builder("t1", "u1", "access")
222    ///     .issuer("auth.example.com")
223    ///     .build();
224    /// assert_eq!(token.issuer.as_deref(), Some("auth.example.com"));
225    /// ```
226    pub fn issuer(mut self, issuer: impl Into<String>) -> Self {
227        self.issuer = Some(issuer.into());
228        self
229    }
230
231    /// Set the refresh token.
232    ///
233    /// # Example
234    ///
235    /// ```rust
236    /// use auth_framework::tokens::AuthToken;
237    ///
238    /// let token = AuthToken::builder("t1", "u1", "access")
239    ///     .refresh_token("refresh_token_value")
240    ///     .build();
241    /// assert!(token.refresh_token.is_some());
242    /// ```
243    pub fn refresh_token(mut self, refresh_token: impl Into<String>) -> Self {
244        self.refresh_token = Some(refresh_token.into());
245        self
246    }
247
248    /// Set the issued timestamp.
249    ///
250    /// # Example
251    ///
252    /// ```rust
253    /// use auth_framework::tokens::AuthToken;
254    /// use chrono::Utc;
255    ///
256    /// let now = Utc::now();
257    /// let token = AuthToken::builder("t1", "u1", "access")
258    ///     .issued_at(now)
259    ///     .build();
260    /// assert_eq!(token.issued_at, now);
261    /// ```
262    pub fn issued_at(mut self, issued_at: DateTime<Utc>) -> Self {
263        self.issued_at = issued_at;
264        self
265    }
266
267    /// Set the expiration timestamp.
268    ///
269    /// # Example
270    ///
271    /// ```rust
272    /// use auth_framework::tokens::AuthToken;
273    /// use chrono::{Utc, Duration};
274    ///
275    /// let expires = Utc::now() + Duration::hours(2);
276    /// let token = AuthToken::builder("t1", "u1", "access")
277    ///     .expires_at(expires)
278    ///     .build();
279    /// ```
280    pub fn expires_at(mut self, expires_at: DateTime<Utc>) -> Self {
281        self.expires_at = expires_at;
282        self
283    }
284
285    /// Set the granted scopes.
286    ///
287    /// # Example
288    ///
289    /// ```rust
290    /// use auth_framework::tokens::AuthToken;
291    /// use auth_framework::types::Scopes;
292    ///
293    /// let token = AuthToken::builder("t1", "u1", "access")
294    ///     .scopes(Scopes::new(vec!["read".into(), "write".into()]))
295    ///     .build();
296    /// ```
297    pub fn scopes(mut self, scopes: crate::types::Scopes) -> Self {
298        self.scopes = scopes;
299        self
300    }
301
302    /// Set the authentication method.
303    ///
304    /// # Example
305    ///
306    /// ```rust
307    /// use auth_framework::tokens::AuthToken;
308    ///
309    /// let token = AuthToken::builder("t1", "u1", "access")
310    ///     .auth_method("password")
311    ///     .build();
312    /// assert_eq!(token.auth_method, "password");
313    /// ```
314    pub fn auth_method(mut self, auth_method: impl Into<String>) -> Self {
315        self.auth_method = auth_method.into();
316        self
317    }
318
319    /// Set the client ID.
320    ///
321    /// # Example
322    ///
323    /// ```rust
324    /// use auth_framework::tokens::AuthToken;
325    ///
326    /// let token = AuthToken::builder("t1", "u1", "access")
327    ///     .client_id("client-app")
328    ///     .build();
329    /// assert_eq!(token.client_id.as_deref(), Some("client-app"));
330    /// ```
331    pub fn client_id(mut self, client_id: impl Into<String>) -> Self {
332        self.client_id = Some(client_id.into());
333        self
334    }
335
336    /// Set the user profile.
337    ///
338    /// # Example
339    ///
340    /// ```rust,ignore
341    /// use auth_framework::tokens::AuthToken;
342    /// use auth_framework::providers::ProviderProfile;
343    ///
344    /// let profile = ProviderProfile { /* ... */ };
345    /// let token = AuthToken::builder("t1", "u1", "access")
346    ///     .user_profile(profile)
347    ///     .build();
348    /// ```
349    pub fn user_profile(mut self, user_profile: ProviderProfile) -> Self {
350        self.user_profile = Some(user_profile);
351        self
352    }
353
354    /// Set the user permissions.
355    ///
356    /// # Example
357    ///
358    /// ```rust
359    /// use auth_framework::tokens::AuthToken;
360    /// use auth_framework::types::Permissions;
361    ///
362    /// let token = AuthToken::builder("t1", "u1", "access")
363    ///     .permissions(Permissions::new(vec!["admin".into()]))
364    ///     .build();
365    /// ```
366    pub fn permissions(mut self, permissions: crate::types::Permissions) -> Self {
367        self.permissions = permissions;
368        self
369    }
370
371    /// Set the user roles.
372    ///
373    /// # Example
374    ///
375    /// ```rust
376    /// use auth_framework::tokens::AuthToken;
377    /// use auth_framework::types::Roles;
378    ///
379    /// let token = AuthToken::builder("t1", "u1", "access")
380    ///     .roles(Roles::new(vec!["editor".into()]))
381    ///     .build();
382    /// ```
383    pub fn roles(mut self, roles: crate::types::Roles) -> Self {
384        self.roles = roles;
385        self
386    }
387
388    /// Set the token metadata.
389    ///
390    /// # Example
391    ///
392    /// ```rust
393    /// use auth_framework::tokens::{AuthToken, TokenMetadata};
394    ///
395    /// let meta = TokenMetadata::builder().issued_ip("10.0.0.1").build();
396    /// let token = AuthToken::builder("t1", "u1", "access")
397    ///     .metadata(meta)
398    ///     .build();
399    /// ```
400    pub fn metadata(mut self, metadata: TokenMetadata) -> Self {
401        self.metadata = metadata;
402        self
403    }
404
405    /// Build the `AuthToken` instance.
406    ///
407    /// # Example
408    ///
409    /// ```rust
410    /// use auth_framework::tokens::AuthToken;
411    ///
412    /// let token = AuthToken::builder("t1", "u1", "access").build();
413    /// assert_eq!(token.user_id, "u1");
414    /// ```
415    pub fn build(self) -> AuthToken {
416        AuthToken {
417            token_id: self.token_id,
418            user_id: self.user_id,
419            access_token: self.access_token,
420            token_type: self.token_type,
421            subject: self.subject,
422            issuer: self.issuer,
423            refresh_token: self.refresh_token,
424            issued_at: self.issued_at,
425            expires_at: self.expires_at,
426            scopes: self.scopes,
427            auth_method: self.auth_method,
428            client_id: self.client_id,
429            user_profile: self.user_profile,
430            permissions: self.permissions,
431            roles: self.roles,
432            metadata: self.metadata,
433        }
434    }
435}
436
437impl AuthToken {
438    /// Start building an `AuthToken` with fluent setters.
439    ///
440    /// # Example
441    ///
442    /// ```rust
443    /// use auth_framework::tokens::AuthToken;
444    ///
445    /// let token = AuthToken::builder("token123", "user456", "access_token")
446    ///     .expires_at(chrono::Utc::now() + chrono::Duration::hours(2))
447    ///     .build();
448    /// ```
449    pub fn builder(
450        token_id: impl Into<String>,
451        user_id: impl Into<String>,
452        access_token: impl Into<String>,
453    ) -> AuthTokenBuilder {
454        AuthTokenBuilder::new(token_id, user_id, access_token)
455    }
456}
457
458/// Contextual information attached to a token at issuance time.
459///
460/// Tracks revocation state, usage counters, and client fingerprints
461/// (IP, user-agent, device).  Defaults to an empty / non-revoked state.
462#[derive(Debug, Clone, Serialize, Deserialize, Default)]
463pub struct TokenMetadata {
464    /// IP address where the token was issued
465    pub issued_ip: Option<String>,
466
467    /// User agent of the client
468    pub user_agent: Option<String>,
469
470    /// Device identifier
471    pub device_id: Option<String>,
472
473    /// Session identifier
474    pub session_id: Option<String>,
475
476    /// Whether this token has been revoked
477    pub revoked: bool,
478
479    /// When the token was revoked (if applicable)
480    pub revoked_at: Option<DateTime<Utc>>,
481
482    /// Reason for revocation
483    pub revoked_reason: Option<String>,
484
485    /// Last time this token was used
486    pub last_used: Option<DateTime<Utc>>,
487
488    /// Number of times this token has been used
489    pub use_count: u64,
490
491    /// Custom metadata
492    pub custom: HashMap<String, serde_json::Value>,
493}
494
495impl TokenMetadata {
496    /// Start building a `TokenMetadata` with fluent setters.
497    ///
498    /// # Example
499    ///
500    /// ```rust
501    /// use auth_framework::tokens::TokenMetadata;
502    /// let meta = TokenMetadata::builder()
503    ///     .issued_ip("10.0.0.1")
504    ///     .user_agent("curl/8.0")
505    ///     .device_id("device-abc")
506    ///     .build();
507    /// assert_eq!(meta.issued_ip.as_deref(), Some("10.0.0.1"));
508    /// ```
509    pub fn builder() -> TokenMetadataBuilder {
510        TokenMetadataBuilder::default()
511    }
512}
513
514/// Fluent builder for [`TokenMetadata`].
515#[derive(Debug, Clone, Default)]
516pub struct TokenMetadataBuilder {
517    inner: TokenMetadata,
518}
519
520impl TokenMetadataBuilder {
521    /// Set the IP address that issued the token.
522    ///
523    /// # Example
524    ///
525    /// ```rust
526    /// use auth_framework::tokens::TokenMetadata;
527    ///
528    /// let meta = TokenMetadata::builder().issued_ip("10.0.0.1").build();
529    /// assert_eq!(meta.issued_ip.as_deref(), Some("10.0.0.1"));
530    /// ```
531    pub fn issued_ip(mut self, ip: impl Into<String>) -> Self {
532        self.inner.issued_ip = Some(ip.into());
533        self
534    }
535
536    /// Set the user-agent string of the issuing client.
537    ///
538    /// # Example
539    ///
540    /// ```rust
541    /// use auth_framework::tokens::TokenMetadata;
542    ///
543    /// let meta = TokenMetadata::builder().user_agent("curl/8.0").build();
544    /// assert_eq!(meta.user_agent.as_deref(), Some("curl/8.0"));
545    /// ```
546    pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
547        self.inner.user_agent = Some(ua.into());
548        self
549    }
550
551    /// Set the device identifier.
552    ///
553    /// # Example
554    ///
555    /// ```rust
556    /// use auth_framework::tokens::TokenMetadata;
557    ///
558    /// let meta = TokenMetadata::builder().device_id("phone-123").build();
559    /// assert_eq!(meta.device_id.as_deref(), Some("phone-123"));
560    /// ```
561    pub fn device_id(mut self, id: impl Into<String>) -> Self {
562        self.inner.device_id = Some(id.into());
563        self
564    }
565
566    /// Set the associated session identifier.
567    ///
568    /// # Example
569    ///
570    /// ```rust
571    /// use auth_framework::tokens::TokenMetadata;
572    ///
573    /// let meta = TokenMetadata::builder().session_id("sess-abc").build();
574    /// assert_eq!(meta.session_id.as_deref(), Some("sess-abc"));
575    /// ```
576    pub fn session_id(mut self, id: impl Into<String>) -> Self {
577        self.inner.session_id = Some(id.into());
578        self
579    }
580
581    /// Insert a custom metadata entry.
582    ///
583    /// # Example
584    ///
585    /// ```rust
586    /// use auth_framework::tokens::TokenMetadata;
587    ///
588    /// let meta = TokenMetadata::builder()
589    ///     .custom("region", serde_json::json!("us-east-1"))
590    ///     .build();
591    /// assert_eq!(meta.custom.get("region").unwrap(), "us-east-1");
592    /// ```
593    pub fn custom(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
594        self.inner.custom.insert(key.into(), value);
595        self
596    }
597
598    /// Consume the builder and return the finished [`TokenMetadata`].
599    ///
600    /// # Example
601    ///
602    /// ```rust
603    /// use auth_framework::tokens::TokenMetadata;
604    ///
605    /// let meta = TokenMetadata::builder()
606    ///     .issued_ip("127.0.0.1")
607    ///     .user_agent("test-client")
608    ///     .build();
609    /// assert!(!meta.revoked);
610    /// ```
611    pub fn build(self) -> TokenMetadata {
612        self.inner
613    }
614}
615
616#[cfg(feature = "postgres-storage")]
617use sqlx::{Decode, Postgres, Type, postgres::PgValueRef};
618
619#[cfg(feature = "postgres-storage")]
620impl<'r> Decode<'r, Postgres> for TokenMetadata {
621    fn decode(value: PgValueRef<'r>) -> std::result::Result<Self, sqlx::error::BoxDynError> {
622        let json: serde_json::Value = <serde_json::Value as Decode<Postgres>>::decode(value)?;
623        serde_json::from_value(json).map_err(|e| Box::new(e) as sqlx::error::BoxDynError)
624    }
625}
626
627#[cfg(feature = "postgres-storage")]
628impl Type<Postgres> for TokenMetadata {
629    fn type_info() -> sqlx::postgres::PgTypeInfo {
630        <serde_json::Value as Type<Postgres>>::type_info()
631    }
632    fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
633        <serde_json::Value as Type<Postgres>>::compatible(ty)
634    }
635}
636
637/// Lightweight user information extracted from a validated token.
638///
639/// Returned by [`AuthFramework::get_token_info`](crate::auth::AuthFramework)
640/// after token validation succeeds.
641#[derive(Debug, Clone, Serialize, Deserialize)]
642pub struct TokenInfo {
643    /// User identifier
644    pub user_id: String,
645
646    /// Username or email
647    pub username: Option<String>,
648
649    /// User's email address
650    pub email: Option<String>,
651
652    /// User's display name
653    pub name: Option<String>,
654
655    /// User's roles
656    pub roles: Vec<String>,
657
658    /// User's permissions
659    pub permissions: Vec<String>,
660
661    /// Additional user attributes
662    pub attributes: HashMap<String, serde_json::Value>,
663}
664
665/// Standard and custom JWT claims used by [`TokenManager`].
666///
667/// Fields follow the [JWT RFC 7519](https://tools.ietf.org/html/rfc7519)
668/// registered claim names.  Additional claims can be stored in [`custom`](JwtClaims::custom).
669#[derive(Debug, Clone, Serialize, Deserialize)]
670pub struct JwtClaims {
671    /// Subject (user ID)
672    pub sub: String,
673
674    /// Issuer
675    pub iss: String,
676
677    /// Audience
678    pub aud: String,
679
680    /// Expiration time
681    pub exp: i64,
682
683    /// Issued at
684    pub iat: i64,
685
686    /// Not before
687    pub nbf: i64,
688
689    /// JWT ID
690    pub jti: String,
691
692    /// Scopes
693    pub scope: String,
694
695    /// User permissions
696    pub permissions: Option<Vec<String>>,
697
698    /// User roles
699    pub roles: Option<Vec<String>>,
700
701    /// Client ID
702    pub client_id: Option<String>,
703
704    /// Custom claims
705    #[serde(flatten)]
706    pub custom: HashMap<String, serde_json::Value>,
707}
708
709/// Central token lifecycle manager: creation, validation, refresh, and
710/// revocation.
711///
712/// Constructed internally by [`AuthFramework`](crate::auth::AuthFramework)
713/// — most users interact with token operations through the
714/// [`TokenOperations`](crate::auth::TokenOperations) facade instead.
715pub struct TokenManager {
716    /// JWT encoding key
717    encoding_key: EncodingKey,
718
719    /// JWT decoding key (current)
720    decoding_key: DecodingKey,
721
722    /// Optional previous decoding key retained during key-rotation grace period.
723    ///
724    /// Tokens signed with the previous key are still accepted until they expire
725    /// naturally.  Once operators are satisfied all pre-rotation tokens have
726    /// expired, they can call [`TokenManager::retire_previous_key`] to remove it.
727    previous_decoding_key: Option<DecodingKey>,
728
729    /// Key material for recreating keys during clone
730    key_material: KeyMaterial,
731
732    /// Key material for the previous key (for clone support after rotation)
733    previous_key_material: Option<KeyMaterial>,
734
735    /// JWT algorithm
736    algorithm: Algorithm,
737
738    /// Token issuer
739    issuer: String,
740
741    /// Token audience
742    audience: String,
743
744    /// Default token lifetime
745    default_lifetime: Duration,
746}
747
748/// Key material for cloning TokenManager
749#[derive(Clone)]
750enum KeyMaterial {
751    /// HMAC secret
752    Hmac(Vec<u8>),
753    /// RSA private and public keys
754    Rsa { private: Vec<u8>, public: Vec<u8> },
755}
756
757/// Public key material that can be serialized into a JWKS document.
758///
759/// Contains the RSA key components needed for JWT verification by external
760/// clients. Typically exposed via a `/.well-known/jwks.json` endpoint.
761#[derive(Debug, Clone, Serialize, Deserialize)]
762pub struct JwksPublicKey {
763    /// The JWT signing algorithm (e.g., RS256).
764    pub algorithm: Algorithm,
765    /// Key ID uniquely identifying this key in the JWKS key set.
766    pub kid: String,
767    /// RSA modulus, base64url-encoded.
768    pub n: String,
769    /// RSA public exponent, base64url-encoded.
770    pub e: String,
771}
772
773impl AuthToken {
774    /// Create a new authentication token.
775    pub fn new(
776        user_id: impl Into<String>,
777        access_token: impl Into<String>,
778        expires_in: std::time::Duration,
779        auth_method: impl Into<String>,
780    ) -> Self {
781        let now = Utc::now();
782        let expires_in_chrono =
783            chrono::Duration::from_std(expires_in).unwrap_or(chrono::Duration::hours(1));
784
785        Self {
786            token_id: Uuid::new_v4().to_string(),
787            user_id: user_id.into(),
788            access_token: access_token.into(),
789            refresh_token: None,
790            token_type: Some("Bearer".to_string()),
791            subject: None,
792            issuer: None,
793            issued_at: now,
794            expires_at: now + expires_in_chrono,
795            scopes: crate::types::Scopes::empty(),
796            auth_method: auth_method.into(),
797            client_id: None,
798            user_profile: None,
799            permissions: crate::types::Permissions::empty(),
800            roles: crate::types::Roles::empty(),
801            metadata: TokenMetadata::default(),
802        }
803    }
804
805    /// Get the access token string.
806    ///
807    /// # Example
808    ///
809    /// ```rust
810    /// use auth_framework::tokens::AuthToken;
811    ///
812    /// let token = AuthToken::builder("t1", "u1", "my_token").build();
813    /// assert_eq!(token.access_token(), "my_token");
814    /// ```
815    pub fn access_token(&self) -> &str {
816        &self.access_token
817    }
818
819    /// Get the user ID.
820    ///
821    /// # Example
822    ///
823    /// ```rust
824    /// use auth_framework::tokens::AuthToken;
825    ///
826    /// let token = AuthToken::builder("t1", "user42", "access").build();
827    /// assert_eq!(token.user_id(), "user42");
828    /// ```
829    pub fn user_id(&self) -> &str {
830        &self.user_id
831    }
832
833    /// Get the expiration time.
834    ///
835    /// # Example
836    ///
837    /// ```rust
838    /// use auth_framework::tokens::AuthToken;
839    /// use chrono::Utc;
840    ///
841    /// let token = AuthToken::builder("t1", "u1", "access").build();
842    /// assert!(token.expires_at() > Utc::now());
843    /// ```
844    pub fn expires_at(&self) -> DateTime<Utc> {
845        self.expires_at
846    }
847
848    /// Get the token value.
849    ///
850    /// Alias for [`access_token()`](Self::access_token).
851    ///
852    /// # Example
853    ///
854    /// ```rust
855    /// use auth_framework::tokens::AuthToken;
856    ///
857    /// let token = AuthToken::builder("t1", "u1", "tok_value").build();
858    /// assert_eq!(token.token_value(), "tok_value");
859    /// ```
860    pub fn token_value(&self) -> &str {
861        &self.access_token
862    }
863
864    /// Get the token type.
865    ///
866    /// # Example
867    ///
868    /// ```rust
869    /// use auth_framework::tokens::AuthToken;
870    ///
871    /// let token = AuthToken::builder("t1", "u1", "access")
872    ///     .token_type("Bearer")
873    ///     .build();
874    /// assert_eq!(token.token_type(), Some("Bearer"));
875    /// ```
876    pub fn token_type(&self) -> Option<&str> {
877        self.token_type.as_deref()
878    }
879
880    /// Get the subject claim.
881    ///
882    /// # Example
883    ///
884    /// ```rust
885    /// use auth_framework::tokens::AuthToken;
886    ///
887    /// let token = AuthToken::builder("t1", "u1", "access")
888    ///     .subject("sub-123")
889    ///     .build();
890    /// assert_eq!(token.subject(), Some("sub-123"));
891    /// ```
892    pub fn subject(&self) -> Option<&str> {
893        self.subject.as_deref()
894    }
895
896    /// Get the issuer.
897    ///
898    /// # Example
899    ///
900    /// ```rust
901    /// use auth_framework::tokens::AuthToken;
902    ///
903    /// let token = AuthToken::builder("t1", "u1", "access")
904    ///     .issuer("my-service")
905    ///     .build();
906    /// assert_eq!(token.issuer(), Some("my-service"));
907    /// ```
908    pub fn issuer(&self) -> Option<&str> {
909        self.issuer.as_deref()
910    }
911
912    /// Check if the token has expired.
913    ///
914    /// # Example
915    ///
916    /// ```rust
917    /// use auth_framework::tokens::AuthToken;
918    ///
919    /// let token = AuthToken::builder("t1", "u1", "access").build();
920    /// assert!(!token.is_expired()); // 1-hour default
921    /// ```
922    pub fn is_expired(&self) -> bool {
923        Utc::now() > self.expires_at
924    }
925
926    /// Check if the token is expiring within the given duration.
927    ///
928    /// # Example
929    ///
930    /// ```rust
931    /// use auth_framework::tokens::AuthToken;
932    /// use std::time::Duration;
933    ///
934    /// let token = AuthToken::builder("t1", "u1", "access").build();
935    /// assert!(token.is_expiring(Duration::from_secs(7200))); // within 2 hours
936    /// ```
937    pub fn is_expiring(&self, within: Duration) -> bool {
938        Utc::now() + within > self.expires_at
939    }
940
941    /// Check if the token has been revoked.
942    ///
943    /// # Example
944    ///
945    /// ```rust
946    /// use auth_framework::tokens::AuthToken;
947    ///
948    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
949    /// assert!(!token.is_revoked());
950    /// token.revoke(Some("user request".to_string()));
951    /// assert!(token.is_revoked());
952    /// ```
953    pub fn is_revoked(&self) -> bool {
954        self.metadata.revoked
955    }
956
957    /// Check if the token is valid (not expired and not revoked).
958    ///
959    /// # Example
960    ///
961    /// ```rust
962    /// use auth_framework::tokens::AuthToken;
963    ///
964    /// let token = AuthToken::builder("t1", "u1", "access").build();
965    /// assert!(token.is_valid());
966    /// ```
967    pub fn is_valid(&self) -> bool {
968        !self.is_expired() && !self.is_revoked()
969    }
970
971    /// Check whether this token carries a refresh token.
972    ///
973    /// # Example
974    ///
975    /// ```rust
976    /// use auth_framework::tokens::AuthToken;
977    ///
978    /// let token = AuthToken::builder("t1", "u1", "access")
979    ///     .refresh_token("rt-abc")
980    ///     .build();
981    /// assert!(token.has_refresh_token());
982    /// ```
983    pub fn has_refresh_token(&self) -> bool {
984        self.refresh_token.is_some()
985    }
986
987    /// Return the refresh token string, if present.
988    ///
989    /// # Example
990    ///
991    /// ```rust
992    /// use auth_framework::tokens::AuthToken;
993    ///
994    /// let token = AuthToken::builder("t1", "u1", "access")
995    ///     .refresh_token("rt-xyz")
996    ///     .build();
997    /// assert_eq!(token.get_refresh_token(), Some("rt-xyz"));
998    /// ```
999    pub fn get_refresh_token(&self) -> Option<&str> {
1000        self.refresh_token.as_deref()
1001    }
1002
1003    /// Revoke the token.
1004    ///
1005    /// # Example
1006    ///
1007    /// ```rust
1008    /// use auth_framework::tokens::AuthToken;
1009    ///
1010    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1011    /// token.revoke(Some("compromised".to_string()));
1012    /// assert!(token.is_revoked());
1013    /// ```
1014    pub fn revoke(&mut self, reason: Option<String>) {
1015        self.metadata.revoked = true;
1016        self.metadata.revoked_at = Some(Utc::now());
1017        self.metadata.revoked_reason = reason;
1018    }
1019
1020    /// Update the last used time and increment use count.
1021    ///
1022    /// # Example
1023    ///
1024    /// ```rust
1025    /// use auth_framework::tokens::AuthToken;
1026    ///
1027    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1028    /// assert_eq!(token.metadata.use_count, 0);
1029    /// token.mark_used();
1030    /// assert_eq!(token.metadata.use_count, 1);
1031    /// ```
1032    pub fn mark_used(&mut self) {
1033        self.metadata.last_used = Some(Utc::now());
1034        self.metadata.use_count += 1;
1035    }
1036
1037    /// Add a scope to the token.
1038    ///
1039    /// Duplicates are ignored.
1040    ///
1041    /// # Example
1042    ///
1043    /// ```rust
1044    /// use auth_framework::tokens::AuthToken;
1045    ///
1046    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1047    /// token.add_scope("read");
1048    /// assert!(token.has_scope("read"));
1049    /// ```
1050    pub fn add_scope(&mut self, scope: impl Into<String>) {
1051        let scope = scope.into();
1052        if !self.scopes.contains(&scope) {
1053            self.scopes.push(scope);
1054        }
1055    }
1056
1057    /// Check if the token has a specific scope.
1058    ///
1059    /// # Example
1060    ///
1061    /// ```rust
1062    /// use auth_framework::tokens::AuthToken;
1063    ///
1064    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1065    /// token.add_scope("write");
1066    /// assert!(token.has_scope("write"));
1067    /// assert!(!token.has_scope("admin"));
1068    /// ```
1069    pub fn has_scope(&self, scope: &str) -> bool {
1070        self.scopes.contains(&scope.to_string())
1071    }
1072
1073    /// Set the refresh token.
1074    ///
1075    /// # Example
1076    ///
1077    /// ```rust
1078    /// use auth_framework::tokens::AuthToken;
1079    ///
1080    /// let token = AuthToken::builder("t1", "u1", "access").build()
1081    ///     .with_refresh_token("refresh_xyz");
1082    /// assert!(token.refresh_token.is_some());
1083    /// ```
1084    pub fn with_refresh_token(mut self, refresh_token: impl Into<String>) -> Self {
1085        self.refresh_token = Some(refresh_token.into());
1086        self
1087    }
1088
1089    /// Set the client ID.
1090    ///
1091    /// # Example
1092    ///
1093    /// ```rust
1094    /// use auth_framework::tokens::AuthToken;
1095    ///
1096    /// let token = AuthToken::builder("t1", "u1", "access").build()
1097    ///     .with_client_id("app-client");
1098    /// assert_eq!(token.client_id.as_deref(), Some("app-client"));
1099    /// ```
1100    pub fn with_client_id(mut self, client_id: impl Into<String>) -> Self {
1101        self.client_id = Some(client_id.into());
1102        self
1103    }
1104
1105    /// Set the token scopes.
1106    ///
1107    /// # Example
1108    ///
1109    /// ```rust
1110    /// use auth_framework::tokens::AuthToken;
1111    /// use auth_framework::types::Scopes;
1112    ///
1113    /// let token = AuthToken::builder("t1", "u1", "access").build()
1114    ///     .with_scopes(Scopes::new(vec!["read".into()]));
1115    /// assert!(token.has_scope("read"));
1116    /// ```
1117    pub fn with_scopes(mut self, scopes: impl Into<crate::types::Scopes>) -> Self {
1118        self.scopes = scopes.into();
1119        self
1120    }
1121
1122    /// Add metadata to the token.
1123    ///
1124    /// # Example
1125    ///
1126    /// ```rust
1127    /// use auth_framework::tokens::{AuthToken, TokenMetadata};
1128    ///
1129    /// let meta = TokenMetadata::builder().issued_ip("192.168.1.1").build();
1130    /// let token = AuthToken::builder("t1", "u1", "access").build()
1131    ///     .with_metadata(meta);
1132    /// assert_eq!(token.metadata.issued_ip.as_deref(), Some("192.168.1.1"));
1133    /// ```
1134    pub fn with_metadata(mut self, metadata: TokenMetadata) -> Self {
1135        self.metadata = metadata;
1136        self
1137    }
1138
1139    /// Get time until expiration.
1140    ///
1141    /// Returns `Duration::ZERO` if the token has already expired.
1142    ///
1143    /// # Example
1144    ///
1145    /// ```rust
1146    /// use auth_framework::tokens::AuthToken;
1147    /// use std::time::Duration;
1148    ///
1149    /// let token = AuthToken::builder("t1", "u1", "access").build();
1150    /// assert!(token.time_until_expiry() > Duration::ZERO);
1151    /// ```
1152    pub fn time_until_expiry(&self) -> Duration {
1153        let now = Utc::now();
1154        if self.expires_at > now {
1155            (self.expires_at - now).to_std().unwrap_or(Duration::ZERO)
1156        } else {
1157            Duration::ZERO
1158        }
1159    }
1160
1161    /// Add a custom claim to the token metadata.
1162    ///
1163    /// # Example
1164    ///
1165    /// ```rust
1166    /// use auth_framework::tokens::AuthToken;
1167    ///
1168    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1169    /// token.add_custom_claim("tenant", serde_json::json!("acme"));
1170    /// assert_eq!(token.get_custom_claim("tenant").unwrap(), &serde_json::json!("acme"));
1171    /// ```
1172    pub fn add_custom_claim(&mut self, key: impl Into<String>, value: serde_json::Value) {
1173        self.metadata.custom.insert(key.into(), value);
1174    }
1175
1176    /// Get a custom claim from the token metadata.
1177    ///
1178    /// # Example
1179    ///
1180    /// ```rust
1181    /// use auth_framework::tokens::AuthToken;
1182    ///
1183    /// let token = AuthToken::builder("t1", "u1", "access").build();
1184    /// assert!(token.get_custom_claim("missing").is_none());
1185    /// ```
1186    pub fn get_custom_claim(&self, key: &str) -> Option<&serde_json::Value> {
1187        self.metadata.custom.get(key)
1188    }
1189
1190    /// Check if the token has a specific permission.
1191    ///
1192    /// # Example
1193    ///
1194    /// ```rust
1195    /// use auth_framework::tokens::AuthToken;
1196    ///
1197    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1198    /// token.add_permission("admin");
1199    /// assert!(token.has_permission("admin"));
1200    /// ```
1201    pub fn has_permission(&self, permission: &str) -> bool {
1202        self.permissions.contains(&permission.to_string())
1203    }
1204
1205    /// Add a permission to the token.
1206    ///
1207    /// Duplicates are ignored.
1208    ///
1209    /// # Example
1210    ///
1211    /// ```rust
1212    /// use auth_framework::tokens::AuthToken;
1213    ///
1214    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1215    /// token.add_permission("write");
1216    /// assert!(token.has_permission("write"));
1217    /// ```
1218    pub fn add_permission(&mut self, permission: impl Into<String>) {
1219        let permission = permission.into();
1220        if !self.permissions.contains(&permission) {
1221            self.permissions.push(permission);
1222        }
1223    }
1224
1225    /// Add a role to the token.
1226    ///
1227    /// Duplicates are ignored.
1228    ///
1229    /// # Example
1230    ///
1231    /// ```rust
1232    /// use auth_framework::tokens::AuthToken;
1233    ///
1234    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1235    /// token.add_role("editor");
1236    /// assert!(token.has_role("editor"));
1237    /// ```
1238    pub fn add_role(&mut self, role: impl Into<String>) {
1239        let role = role.into();
1240        if !self.roles.contains(&role) {
1241            self.roles.push(role);
1242        }
1243    }
1244
1245    /// Check if the token has a specific role.
1246    ///
1247    /// # Example
1248    ///
1249    /// ```rust
1250    /// use auth_framework::tokens::AuthToken;
1251    ///
1252    /// let mut token = AuthToken::builder("t1", "u1", "access").build();
1253    /// token.add_role("admin");
1254    /// assert!(token.has_role("admin"));
1255    /// assert!(!token.has_role("guest"));
1256    /// ```
1257    pub fn has_role(&self, role: &str) -> bool {
1258        self.roles.contains(&role.to_string())
1259    }
1260
1261    /// Set the permissions.
1262    ///
1263    /// # Example
1264    ///
1265    /// ```rust
1266    /// use auth_framework::tokens::AuthToken;
1267    /// use auth_framework::types::Permissions;
1268    ///
1269    /// let token = AuthToken::builder("t1", "u1", "access").build()
1270    ///     .with_permissions(Permissions::new(vec!["read".into()]));
1271    /// assert!(token.has_permission("read"));
1272    /// ```
1273    pub fn with_permissions(mut self, permissions: impl Into<crate::types::Permissions>) -> Self {
1274        self.permissions = permissions.into();
1275        self
1276    }
1277
1278    /// Set the roles.
1279    ///
1280    /// # Example
1281    ///
1282    /// ```rust
1283    /// use auth_framework::tokens::AuthToken;
1284    /// use auth_framework::types::Roles;
1285    ///
1286    /// let token = AuthToken::builder("t1", "u1", "access").build()
1287    ///     .with_roles(Roles::new(vec!["viewer".into()]));
1288    /// assert!(token.has_role("viewer"));
1289    /// ```
1290    pub fn with_roles(mut self, roles: impl Into<crate::types::Roles>) -> Self {
1291        self.roles = roles.into();
1292        self
1293    }
1294}
1295
1296impl Clone for TokenManager {
1297    fn clone(&self) -> Self {
1298        let (previous_decoding_key, previous_key_material) = match &self.previous_key_material {
1299            Some(KeyMaterial::Hmac(secret)) => (
1300                Some(DecodingKey::from_secret(secret)),
1301                Some(KeyMaterial::Hmac(secret.clone())),
1302            ),
1303            Some(KeyMaterial::Rsa { public, .. }) => (
1304                DecodingKey::from_rsa_pem(public).ok(),
1305                self.previous_key_material.clone(),
1306            ),
1307            None => (None, None),
1308        };
1309        match &self.key_material {
1310            KeyMaterial::Hmac(secret) => Self {
1311                encoding_key: EncodingKey::from_secret(secret),
1312                decoding_key: DecodingKey::from_secret(secret),
1313                previous_decoding_key,
1314                key_material: self.key_material.clone(),
1315                previous_key_material,
1316                algorithm: self.algorithm,
1317                issuer: self.issuer.clone(),
1318                audience: self.audience.clone(),
1319                default_lifetime: self.default_lifetime,
1320            },
1321            KeyMaterial::Rsa { private, public } => Self {
1322                // SAFETY: The PEM was already validated when the TokenManager was first
1323                // constructed; re-parsing it here during Clone cannot fail unless the
1324                // bytes were corrupted in memory, which would be a catastrophic bug.
1325                encoding_key: EncodingKey::from_rsa_pem(private).expect("RSA private key PEM re-parse failed during Clone — this indicates memory corruption"),
1326                decoding_key: DecodingKey::from_rsa_pem(public).expect("RSA public key PEM re-parse failed during Clone — this indicates memory corruption"),
1327                previous_decoding_key,
1328                key_material: self.key_material.clone(),
1329                previous_key_material,
1330                algorithm: self.algorithm,
1331                issuer: self.issuer.clone(),
1332                audience: self.audience.clone(),
1333                default_lifetime: self.default_lifetime,
1334            },
1335        }
1336    }
1337}
1338
1339impl TokenManager {
1340    fn jwks_from_public_pem(public_key: &[u8], algorithm: Algorithm) -> Result<JwksPublicKey> {
1341        let pem = std::str::from_utf8(public_key)
1342            .map_err(|e| AuthError::crypto(format!("Invalid RSA public key PEM encoding: {e}")))?;
1343
1344        let public_key = rsa::RsaPublicKey::from_public_key_pem(pem)
1345            .or_else(|_| rsa::RsaPublicKey::from_pkcs1_pem(pem))
1346            .map_err(|e| {
1347                AuthError::crypto(format!(
1348                    "Failed to parse RSA public key for JWKS export: {e}"
1349                ))
1350            })?;
1351
1352        let modulus = public_key.n().to_bytes_be();
1353        let exponent = public_key.e().to_bytes_be();
1354        let kid_digest = Sha256::digest(&modulus);
1355
1356        let n = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&modulus);
1357        let e = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&exponent);
1358        let kid = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(kid_digest);
1359
1360        Ok(JwksPublicKey {
1361            algorithm,
1362            kid,
1363            n,
1364            e,
1365        })
1366    }
1367
1368    /// Export the current and previous RSA verification keys as JWKS-compatible material.
1369    pub fn export_public_jwks(&self) -> Result<Vec<JwksPublicKey>> {
1370        let mut keys = Vec::new();
1371
1372        if let KeyMaterial::Rsa { public, .. } = &self.key_material {
1373            keys.push(Self::jwks_from_public_pem(public, self.algorithm)?);
1374        }
1375
1376        if let Some(KeyMaterial::Rsa { public, .. }) = &self.previous_key_material {
1377            let previous = Self::jwks_from_public_pem(public, self.algorithm)?;
1378            if !keys.iter().any(|key| key.kid == previous.kid) {
1379                keys.push(previous);
1380            }
1381        }
1382
1383        Ok(keys)
1384    }
1385
1386    /// Create a new token manager with HMAC key.
1387    pub fn new_hmac(secret: &[u8], issuer: impl Into<String>, audience: impl Into<String>) -> Self {
1388        Self {
1389            encoding_key: EncodingKey::from_secret(secret),
1390            decoding_key: DecodingKey::from_secret(secret),
1391            previous_decoding_key: None,
1392            key_material: KeyMaterial::Hmac(secret.to_vec()),
1393            previous_key_material: None,
1394            algorithm: Algorithm::HS256,
1395            issuer: issuer.into(),
1396            audience: audience.into(),
1397            default_lifetime: Duration::from_secs(3600), // 1 hour
1398        }
1399    }
1400
1401    /// Create a new token manager with RSA keys.
1402    ///
1403    /// ## RSA Key Format Support
1404    ///
1405    /// This method supports RSA keys in both standard PEM formats:
1406    /// - **PKCS#1**: `-----BEGIN RSA PRIVATE KEY-----` (traditional RSA format)
1407    /// - **PKCS#8**: `-----BEGIN PRIVATE KEY-----` (modern standard format, recommended)
1408    ///
1409    /// Both formats are automatically detected and parsed. No format conversion is required.
1410    ///
1411    /// ## Example
1412    ///
1413    /// ```rust,no_run
1414    /// use auth_framework::tokens::TokenManager;
1415    ///
1416    /// // Both PKCS#1 and PKCS#8 formats work; provide PEM bytes from your key store.
1417    /// # let private_key: &[u8] = b"";
1418    /// # let public_key: &[u8] = b"";
1419    ///
1420    /// let manager = TokenManager::new_rsa(
1421    ///     private_key,
1422    ///     public_key,
1423    ///     "my-service",
1424    ///     "my-audience"
1425    /// )?;
1426    /// # Ok::<(), auth_framework::errors::AuthError>(())
1427    /// ```
1428    pub fn new_rsa(
1429        private_key: &[u8],
1430        public_key: &[u8],
1431        issuer: impl Into<String>,
1432        audience: impl Into<String>,
1433    ) -> Result<Self> {
1434        let encoding_key = EncodingKey::from_rsa_pem(private_key)
1435            .map_err(|e| AuthError::crypto(format!("Invalid RSA private key: {e}")))?;
1436
1437        let decoding_key = DecodingKey::from_rsa_pem(public_key)
1438            .map_err(|e| AuthError::crypto(format!("Invalid RSA public key: {e}")))?;
1439
1440        Ok(Self {
1441            encoding_key,
1442            decoding_key,
1443            previous_decoding_key: None,
1444            key_material: KeyMaterial::Rsa {
1445                private: private_key.to_vec(),
1446                public: public_key.to_vec(),
1447            },
1448            previous_key_material: None,
1449            algorithm: Algorithm::RS256,
1450            issuer: issuer.into(),
1451            audience: audience.into(),
1452            default_lifetime: Duration::from_secs(3600), // 1 hour
1453        })
1454    }
1455
1456    /// Rotate HMAC key, keeping the current key as the previous decoding key
1457    /// to seamlessly allow verification of tokens signed with the old key.
1458    pub fn rotate_hmac_key(&mut self, new_secret: &[u8]) {
1459        // Move current key to previous
1460        if let KeyMaterial::Hmac(secret) = &self.key_material {
1461            self.previous_decoding_key = Some(DecodingKey::from_secret(secret));
1462            self.previous_key_material = Some(KeyMaterial::Hmac(secret.clone()));
1463        }
1464
1465        // Set new key
1466        self.encoding_key = EncodingKey::from_secret(new_secret);
1467        self.decoding_key = DecodingKey::from_secret(new_secret);
1468        self.key_material = KeyMaterial::Hmac(new_secret.to_vec());
1469        self.algorithm = Algorithm::HS256;
1470    }
1471
1472    /// Rotate RSA key, keeping the current key as the previous decoding key
1473    /// to seamlessly allow verification of tokens signed with the old key.
1474    pub fn rotate_rsa_key(&mut self, private_key: &[u8], public_key: &[u8]) -> Result<()> {
1475        let new_encoding_key = EncodingKey::from_rsa_pem(private_key)
1476            .map_err(|e| AuthError::crypto(format!("Invalid RSA private key: {e}")))?;
1477        let new_decoding_key = DecodingKey::from_rsa_pem(public_key)
1478            .map_err(|e| AuthError::crypto(format!("Invalid RSA public key: {e}")))?;
1479
1480        // Move current key to previous
1481        if let KeyMaterial::Rsa { public, .. } = &self.key_material {
1482            self.previous_decoding_key = DecodingKey::from_rsa_pem(public).ok();
1483            self.previous_key_material = Some(self.key_material.clone());
1484        }
1485
1486        // Set new key
1487        self.encoding_key = new_encoding_key;
1488        self.decoding_key = new_decoding_key;
1489        self.key_material = KeyMaterial::Rsa {
1490            private: private_key.to_vec(),
1491            public: public_key.to_vec(),
1492        };
1493        self.algorithm = Algorithm::RS256;
1494
1495        Ok(())
1496    }
1497
1498    /// Retire the previous key (if any), so tokens signed with it are no longer valid.
1499    pub fn retire_previous_key(&mut self) {
1500        self.previous_decoding_key = None;
1501        self.previous_key_material = None;
1502    }
1503
1504    /// Set the default token lifetime.
1505    pub fn with_default_lifetime(mut self, lifetime: Duration) -> Self {
1506        self.default_lifetime = lifetime;
1507        self
1508    }
1509
1510    /// Create a new JWT token.
1511    pub fn create_jwt_token(
1512        &self,
1513        user_id: impl Into<String>,
1514        scopes: Vec<String>,
1515        lifetime: Option<Duration>,
1516    ) -> Result<String> {
1517        let user_id = user_id.into();
1518        let lifetime = lifetime.unwrap_or(self.default_lifetime);
1519        let now = Utc::now();
1520        let exp = now + chrono::Duration::from_std(lifetime).unwrap_or(chrono::Duration::hours(1));
1521
1522        let claims = JwtClaims {
1523            sub: user_id,
1524            iss: self.issuer.clone(),
1525            aud: self.audience.clone(),
1526            exp: exp.timestamp(),
1527            iat: now.timestamp(),
1528            nbf: now.timestamp(),
1529            jti: Uuid::new_v4().to_string(),
1530            scope: scopes.join(" "),
1531            permissions: None,
1532            roles: None,
1533            client_id: None,
1534            custom: HashMap::new(),
1535        };
1536
1537        let header = Header::new(self.algorithm);
1538
1539        encode(&header, &claims, &self.encoding_key)
1540            .map_err(|e| TokenError::creation_failed(format!("JWT encoding failed: {e}")).into())
1541    }
1542
1543    /// Validate and decode a JWT token.
1544    pub fn validate_jwt_token(&self, token: &str) -> Result<JwtClaims> {
1545        let mut validation = Validation::new(self.algorithm);
1546        validation.set_issuer(&[&self.issuer]);
1547        validation.set_audience(&[&self.audience]);
1548
1549        match decode::<JwtClaims>(token, &self.decoding_key, &validation) {
1550            Ok(token_data) => Ok(token_data.claims),
1551            Err(e) => {
1552                match e.kind() {
1553                    jsonwebtoken::errors::ErrorKind::ExpiredSignature => {
1554                        Err(AuthError::Token(TokenError::Expired))
1555                    }
1556                    jsonwebtoken::errors::ErrorKind::InvalidSignature => {
1557                        // If signature is invalid, try the previous key if configured
1558                        if let Some(prev_key) = &self.previous_decoding_key
1559                            && let Ok(prev_token_data) =
1560                                decode::<JwtClaims>(token, prev_key, &validation)
1561                        {
1562                            return Ok(prev_token_data.claims);
1563                        }
1564
1565                        Err(AuthError::Token(TokenError::Invalid {
1566                            message: "Invalid token signature".to_string(),
1567                        }))
1568                    }
1569                    _ => Err(AuthError::Token(TokenError::Invalid {
1570                        message: "Invalid token format".to_string(),
1571                    })),
1572                }
1573            }
1574        }
1575    }
1576
1577    /// Create a complete authentication token with JWT.
1578    pub fn create_auth_token(
1579        &self,
1580        user_id: impl Into<String>,
1581        scopes: impl Into<crate::types::Scopes>,
1582        auth_method: impl Into<String>,
1583        lifetime: Option<std::time::Duration>,
1584    ) -> Result<AuthToken> {
1585        let user_id_str = user_id.into();
1586        let scopes: crate::types::Scopes = scopes.into();
1587        let lifetime = lifetime.unwrap_or(self.default_lifetime);
1588
1589        let jwt_token = self.create_jwt_token(&user_id_str, scopes.to_vec(), Some(lifetime))?;
1590
1591        let token =
1592            AuthToken::new(user_id_str, jwt_token, lifetime, auth_method).with_scopes(scopes);
1593
1594        Ok(token)
1595    }
1596
1597    /// Validate an authentication token.
1598    pub fn validate_auth_token(&self, token: &AuthToken) -> Result<()> {
1599        // Check if token is expired
1600        if token.is_expired() {
1601            return Err(TokenError::Expired.into());
1602        }
1603
1604        // Check if token is revoked
1605        if token.is_revoked() {
1606            return Err(TokenError::Invalid {
1607                message: "Token has been revoked".to_string(),
1608            }
1609            .into());
1610        }
1611
1612        // Validate JWT if it's a JWT token
1613        if token.auth_method == "jwt" || token.access_token.contains('.') {
1614            self.validate_jwt_token(&token.access_token)?;
1615        }
1616
1617        Ok(())
1618    }
1619
1620    /// Refresh a token (create a new one with extended lifetime).
1621    pub fn refresh_token(&self, token: &AuthToken) -> Result<AuthToken> {
1622        if token.is_expired() {
1623            return Err(TokenError::Expired.into());
1624        }
1625
1626        if token.is_revoked() {
1627            return Err(TokenError::Invalid {
1628                message: "Cannot refresh revoked token".to_string(),
1629            }
1630            .into());
1631        }
1632
1633        // Create a new token with the same properties but new expiry
1634        self.create_auth_token(
1635            &token.user_id,
1636            token.scopes.clone(),
1637            &token.auth_method,
1638            Some(self.default_lifetime),
1639        )
1640    }
1641
1642    /// Extract token information from a JWT.
1643    pub fn extract_token_info(&self, token: &str) -> Result<TokenInfo> {
1644        let claims = self.validate_jwt_token(token)?;
1645
1646        Ok(TokenInfo {
1647            user_id: claims.sub,
1648            username: claims
1649                .custom
1650                .get("username")
1651                .and_then(|v| v.as_str())
1652                .map(|s| s.to_string()),
1653            email: claims
1654                .custom
1655                .get("email")
1656                .and_then(|v| v.as_str())
1657                .map(|s| s.to_string()),
1658            name: claims
1659                .custom
1660                .get("name")
1661                .and_then(|v| v.as_str())
1662                .map(|s| s.to_string()),
1663            roles: claims
1664                .custom
1665                .get("roles")
1666                .and_then(|v| v.as_array())
1667                .map(|arr| {
1668                    arr.iter()
1669                        .filter_map(|v| v.as_str())
1670                        .map(|s| s.to_string())
1671                        .collect()
1672                })
1673                .unwrap_or_default(),
1674            permissions: claims
1675                .scope
1676                .split_whitespace()
1677                .map(|s| s.to_string())
1678                .collect(),
1679            attributes: claims.custom,
1680        })
1681    }
1682}
1683
1684/// Trait for converting tokens to user profiles
1685#[async_trait::async_trait]
1686pub trait TokenToProfile {
1687    /// Convert this token to a user profile using the specified provider
1688    async fn to_profile(&self, provider: &OAuthProvider) -> Result<ProviderProfile>;
1689
1690    /// Convert this token to a user profile with a custom extractor
1691    async fn to_profile_with_extractor(
1692        &self,
1693        provider: &OAuthProvider,
1694        extractor: &ProfileExtractor,
1695    ) -> Result<ProviderProfile>;
1696}
1697
1698#[async_trait::async_trait]
1699impl TokenToProfile for AuthToken {
1700    async fn to_profile(&self, provider: &OAuthProvider) -> Result<ProviderProfile> {
1701        let extractor = ProfileExtractor::new();
1702        extractor.extract_profile(self, provider).await
1703    }
1704
1705    async fn to_profile_with_extractor(
1706        &self,
1707        provider: &OAuthProvider,
1708        extractor: &ProfileExtractor,
1709    ) -> Result<ProviderProfile> {
1710        extractor.extract_profile(self, provider).await
1711    }
1712}
1713
1714#[cfg(test)]
1715mod tests {
1716    use super::*;
1717
1718    #[test]
1719    fn test_auth_token_creation() {
1720        let token = AuthToken::new(
1721            "user123",
1722            "token123",
1723            Duration::from_secs(3600), // 1 hour
1724            "password",
1725        );
1726
1727        assert_eq!(token.user_id(), "user123");
1728        assert_eq!(token.access_token(), "token123");
1729        assert!(!token.is_expired());
1730        assert!(!token.is_revoked());
1731        assert!(token.is_valid());
1732    }
1733
1734    #[test]
1735    fn test_token_expiry() {
1736        let token = AuthToken::new("user123", "token123", Duration::from_millis(1), "password");
1737
1738        // Wait a bit to ensure expiry
1739        std::thread::sleep(std::time::Duration::from_millis(10));
1740
1741        assert!(token.is_expired());
1742        assert!(!token.is_valid());
1743    }
1744
1745    #[test]
1746    fn test_token_revocation() {
1747        let mut token = AuthToken::new(
1748            "user123",
1749            "token123",
1750            Duration::from_secs(3600), // 1 hour
1751            "password",
1752        );
1753
1754        assert!(!token.is_revoked());
1755
1756        token.revoke(Some("User logout".to_string()));
1757
1758        assert!(token.is_revoked());
1759        assert!(!token.is_valid());
1760        assert!(token.metadata.revoked);
1761    }
1762}