Skip to main content

supabase_jwt/
claims.rs

1//! # JWT Claims
2//!
3//! This module provides the `Claims` struct, which represents the deserialized data
4//! from a Supabase Auth JWT. It is designed to be a simple data carrier with
5//! convenient methods for accessing standard JWT claims and Supabase-specific metadata.
6//!
7//! The actual JWT parsing and validation logic is handled by the `JwtParser`,
8//! and this module focuses on providing a strongly-typed structure for the claims
9//! once they have been successfully validated.
10
11use crate::{error::AuthError, jwks::JwksCache, parser::JwtParser};
12use serde::{Deserialize, Serialize};
13
14/// Represents the claims of a Supabase JWT.
15///
16/// This struct acts as a data carrier for all the claims contained within a JWT,
17/// making it easy to access user information and metadata. The validation logic
18/// is handled by the `JwtParser` before the claims are instantiated.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Claims {
21    /// (Subject) The user ID.
22    pub sub: String,
23    /// (Expiration Time) The timestamp when the token expires.
24    pub exp: usize,
25    /// (Issued At) The timestamp when the token was issued.
26    pub iat: Option<usize>,
27    /// (JWT ID) A unique identifier for the token.
28    pub jti: Option<String>,
29    /// The user's email address.
30    pub email: Option<String>,
31    /// The user's phone number.
32    pub phone: Option<String>,
33    /// The user's role.
34    pub role: Option<String>,
35    /// Application-specific metadata.
36    pub app_metadata: Option<serde_json::Value>,
37    /// User-specific metadata.
38    pub user_metadata: Option<serde_json::Value>,
39    /// (Audience) The recipient for which the JWT is intended.
40    pub aud: Option<String>,
41    /// (Issuer) The principal that issued the JWT.
42    pub iss: Option<String>,
43    /// (Authentication Assurance Level) The level of assurance.
44    pub aal: Option<String>,
45    /// (Authentication Methods References) A list of authentication methods.
46    pub amr: Option<Vec<serde_json::Value>>,
47    /// The session ID.
48    pub session_id: Option<String>,
49    /// Indicates if the user is anonymous.
50    pub is_anonymous: Option<bool>,
51    /// (Key ID) The ID of the key used to sign the token. Not serialized.
52    #[serde(skip)]
53    pub kid: Option<String>,
54}
55
56impl Claims {
57    /// Parses and validates claims from a raw JWT string.
58    ///
59    /// # Arguments
60    ///
61    /// * `token` - The raw JWT string.
62    /// * `jwks_cache` - A reference to the `JwksCache` for key retrieval.
63    ///
64    /// # Returns
65    ///
66    /// A `Result` containing the validated `Claims` or an `AuthError`.
67    pub async fn from_token(token: &str, jwks_cache: &JwksCache) -> Result<Self, AuthError> {
68        let jwt_header = JwtParser::decode_header(token)?;
69        let kid = jwt_header.kid.ok_or(AuthError::InvalidToken)?;
70
71        let jwk = jwks_cache.find_key(&kid).await?;
72        let decoding_key = JwtParser::create_decoding_key(&jwk)?;
73        let algorithm = JwtParser::parse_algorithm(&jwt_header.alg)?;
74
75        let mut claims = JwtParser::verify_and_decode(token, &decoding_key, algorithm)?;
76        claims.kid = Some(kid);
77
78        claims.validate_security()?;
79
80        Ok(claims)
81    }
82
83    /// Parses and validates claims from a "Bearer" token string.
84    ///
85    /// This method expects the token to be prefixed with "Bearer ".
86    ///
87    /// # Arguments
88    ///
89    /// * `bearer_token` - The Bearer token string (e.g., "Bearer eyJ...").
90    /// * `jwks_cache` - A reference to the `JwksCache` for key retrieval.
91    ///
92    /// # Returns
93    ///
94    /// A `Result` containing the validated `Claims` or an `AuthError`.
95    pub async fn from_bearer_token(
96        bearer_token: &str,
97        jwks_cache: &JwksCache,
98    ) -> Result<Self, AuthError> {
99        let token = bearer_token
100            .strip_prefix("Bearer ")
101            .ok_or(AuthError::MalformedToken)?;
102
103        Self::from_token(token, jwks_cache).await
104    }
105
106    /// Performs basic security validation on the claims.
107    ///
108    /// This validation is minimal, trusting that Supabase Auth has already performed
109    /// comprehensive checks. It primarily ensures that the subject (user ID) is not empty.
110    pub fn validate_security(&self) -> Result<(), AuthError> {
111        if self.sub.trim().is_empty() {
112            return Err(AuthError::InvalidClaims);
113        }
114        Ok(())
115    }
116}
117
118// Data access methods
119impl Claims {
120    /// Returns the user ID (subject).
121    pub fn user_id(&self) -> &str {
122        &self.sub
123    }
124
125    /// Returns the user's email, if available.
126    pub fn email(&self) -> Option<&str> {
127        self.email.as_deref()
128    }
129
130    /// Returns the user's role, defaulting to "authenticated".
131    pub fn role(&self) -> &str {
132        self.role.as_deref().unwrap_or("authenticated")
133    }
134
135    /// Returns the user's phone number, if available.
136    pub fn phone(&self) -> Option<&str> {
137        self.phone.as_deref()
138    }
139
140    /// Checks if the user is anonymous.
141    pub fn is_anonymous(&self) -> bool {
142        self.is_anonymous.unwrap_or(false)
143    }
144}
145
146// Metadata access methods
147impl Claims {
148    /// Retrieves a specific field from the user metadata.
149    ///
150    /// # Arguments
151    ///
152    /// * `key` - The key of the metadata field to retrieve.
153    ///
154    /// # Returns
155    ///
156    /// An `Option` containing the deserialized value if the key exists.
157    pub fn get_user_metadata<T>(&self, key: &str) -> Option<T>
158    where
159        T: serde::de::DeserializeOwned,
160    {
161        self.user_metadata
162            .as_ref()
163            .and_then(|metadata| metadata.get(key))
164            .and_then(|value| serde_json::from_value(value.clone()).ok())
165    }
166
167    /// Retrieves a specific field from the application metadata.
168    ///
169    /// # Arguments
170    ///
171    /// * `key` - The key of the metadata field to retrieve.
172    ///
173    /// # Returns
174    ///
175    /// An `Option` containing the deserialized value if the key exists.
176    pub fn get_app_metadata<T>(&self, key: &str) -> Option<T>
177    where
178        T: serde::de::DeserializeOwned,
179    {
180        self.app_metadata
181            .as_ref()
182            .and_then(|metadata| metadata.get(key))
183            .and_then(|value| serde_json::from_value(value.clone()).ok())
184    }
185}