JWT Claims Reference
Complete reference for claims appearing in JWTs created by Supabase Auth
This page provides a comprehensive reference for all JWT claims used in Supabase authentication tokens. This information is essential for server-side JWT validation and serialization, especially when implementing authentication in languages like Rust where field names like ref are reserved keywords.
JWT structure overview#
Supabase JWTs follow the standard JWT structure with three parts:
- Header: Contains algorithm and key information
- Payload: Contains the claims (user data and metadata)
- Signature: Cryptographic signature for verification
The payload contains various claims that provide user identity, authentication level, and authorization information.
Required claims#
These claims are always present in Supabase JWTs and cannot be removed:
| Field | Type | Description | Example |
|---|---|---|---|
iss | string | Issuer - The entity that issued the JWT | "https://project-ref.supabase.co/auth/v1" |
aud | string | string[] | Audience - The intended recipient of the JWT | "authenticated" or "anon" |
exp | number | Expiration Time - Unix timestamp when the token expires | 1640995200 |
iat | number | Issued At - Unix timestamp when the token was issued | 1640991600 |
sub | string | Subject - The user ID (UUID) | "123e4567-e89b-12d3-a456-426614174000" |
role | string | Role - User's role in the system | "authenticated", "anon", "service_role" |
aal | string | Authenticator Assurance Level - Authentication strength | "aal1", "aal2" |
session_id | string | Session ID - Unique session identifier | "session-uuid" |
email | string | Email - User's email address | "user@example.com" |
phone | string | Phone - User's phone number | "+1234567890" |
is_anonymous | boolean | Anonymous Flag - Whether the user is anonymous | false |
Optional claims#
These claims may be present depending on the authentication context:
| Field | Type | Description | Example |
|---|---|---|---|
jti | string | JWT ID - Unique identifier for the JWT | "jwt-uuid" |
nbf | number | Not Before - Unix timestamp before which the token is invalid | 1640991600 |
app_metadata | object | App Metadata - Application-specific user data | {"provider": "email"} |
user_metadata | object | User Metadata - User-specific data | {"name": "John Doe"} |
amr | array | Authentication Methods Reference - List of authentication methods used | [{"method": "password", "timestamp": 1640991600}] |
Special claims#
| Field | Type | Description | Example | Context |
|---|---|---|---|---|
ref | string | Project Reference - Supabase project identifier | "abcdefghijklmnopqrst" | Anon/Service role tokens only |
Field value constraints#
Authenticator assurance level (aal)#
| Value | Description |
|---|---|
"aal1" | Single-factor authentication (password, OAuth, etc.) |
"aal2" | Multi-factor authentication (password + TOTP, etc.) |
Role values (role)#
| Value | Description | Use Case |
|---|---|---|
"anon" | Anonymous user | Public access with RLS policies |
"authenticated" | Authenticated user | Standard user access |
"service_role" | Service role | Admin privileges (server-side only) |
Audience values (aud)#
| Value | Description |
|---|---|
"authenticated" | For authenticated user tokens |
"anon" | For anonymous user tokens |
Authentication methods (amr.method)#
| Value | Description |
|---|---|
"oauth" | OAuth provider authentication |
"password" | Email/password authentication |
"otp" | One-time password |
"totp" | Time-based one-time password |
"recovery" | Account recovery |
"invite" | Invitation-based signup |
"sso/saml" | SAML single sign-on |
"magiclink" | Magic link authentication |
"email/signup" | Email signup |
"email_change" | Email change |
"token_refresh" | Token refresh |
"anonymous" | Anonymous authentication |
JWT examples#
Authenticated user token#
1{2 "aal": "aal1",3 "amr": [4 {5 "method": "password",6 "timestamp": 16409916007 }8 ],9 "app_metadata": {10 "provider": "email",11 "providers": ["email"]12 },13 "aud": "authenticated",14 "email": "user@example.com",15 "exp": 1640995200,16 "iat": 1640991600,17 "iss": "https://abcdefghijklmnopqrst.supabase.co/auth/v1",18 "phone": "",19 "role": "authenticated",20 "session_id": "123e4567-e89b-12d3-a456-426614174000",21 "sub": "123e4567-e89b-12d3-a456-426614174000",22 "user_metadata": {23 "name": "John Doe"24 },25 "is_anonymous": false26}Anonymous user token#
1{2 "iss": "supabase",3 "ref": "abcdefghijklmnopqrst",4 "role": "anon",5 "iat": 1640991600,6 "exp": 16409952007}Service role token#
1{2 "iss": "supabase",3 "ref": "abcdefghijklmnopqrst",4 "role": "service_role",5 "iat": 1640991600,6 "exp": 16409952007}Language-Specific considerations#
Rust#
In Rust, the ref field is a reserved keyword. When deserializing JWTs, you'll need to handle this:
1use serde::{Deserialize, Serialize};23#[derive(Debug, Deserialize, Serialize)]4struct JwtClaims {5 iss: String,6 #[serde(rename = "ref")] // Handle reserved keyword7 project_ref: Option<String>,8 role: String,9 iat: i64,10 exp: i64,11 // ... other claims12}TypeScript/JavaScript#
1interface {2 : string3 : string | string[]4 : number5 : number6 : string7 : string8 : 'aal1' | 'aal2'9 : string10 : string11 : string12 : boolean13 ?: string14 ?: number15 ?: <string, any>16 ?: <string, any>17 ?: <{18 : string19 : number20 }>21 ?: string // Only in anon/service role tokens22}Python#
1from typing import Optional, Union, List, Dict, Any2from dataclasses import dataclass34@dataclass5class AmrEntry:6 method: str7 timestamp: int89@dataclass10class JwtClaims:11 iss: str12 aud: Union[str, List[str]]13 exp: int14 iat: int15 sub: str16 role: str17 aal: str18 session_id: str19 email: str20 phone: str21 is_anonymous: bool22 jti: Optional[str] = None23 nbf: Optional[int] = None24 app_metadata: Optional[Dict[str, Any]] = None25 user_metadata: Optional[Dict[str, Any]] = None26 amr: Optional[List[AmrEntry]] = None27 ref: Optional[str] = None # Only in anon/service role tokensGo#
1type AmrEntry struct {2 Method string `json:"method"`3 Timestamp int64 `json:"timestamp"`4}56type JwtClaims struct {7 Iss string `json:"iss"`8 Aud interface{} `json:"aud"` // string or []string9 Exp int64 `json:"exp"`10 Iat int64 `json:"iat"`11 Sub string `json:"sub"`12 Role string `json:"role"`13 Aal string `json:"aal"`14 SessionID string `json:"session_id"`15 Email string `json:"email"`16 Phone string `json:"phone"`17 IsAnonymous bool `json:"is_anonymous"`18 Jti *string `json:"jti,omitempty"`19 Nbf *int64 `json:"nbf,omitempty"`20 AppMetadata map[string]interface{} `json:"app_metadata,omitempty"`21 UserMetadata map[string]interface{} `json:"user_metadata,omitempty"`22 Amr []AmrEntry `json:"amr,omitempty"`23 Ref *string `json:"ref,omitempty"` // Only in anon/service role tokens24}Validation guidelines#
When implementing JWT validation on your server:
- Check Required Fields: Ensure all required claims are present
- Validate Types: Verify field types match expected types
- Check Expiration: Validate
exptimestamp is in the future - Verify Issuer: Ensure
issmatches your Supabase project - Check Audience: Validate
audmatches expected audience - Handle Reserved Keywords: Use field renaming for languages like Rust
Security considerations#
- Always validate the JWT signature before trusting any claims
- Never expose service role tokens to client-side code
- Validate all claims before trusting the JWT
- Check token expiration on every request
- Use HTTPS for all JWT transmission
- Rotate JWT secrets regularly
- Implement proper error handling for invalid tokens