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
1234567891011121314151617181920212223242526{  "aal": "aal1",  "amr": [    {      "method": "password",      "timestamp": 1640991600    }  ],  "app_metadata": {    "provider": "email",    "providers": ["email"]  },  "aud": "authenticated",  "email": "user@example.com",  "exp": 1640995200,  "iat": 1640991600,  "iss": "https://abcdefghijklmnopqrst.supabase.co/auth/v1",  "phone": "",  "role": "authenticated",  "session_id": "123e4567-e89b-12d3-a456-426614174000",  "sub": "123e4567-e89b-12d3-a456-426614174000",  "user_metadata": {    "name": "John Doe"  },  "is_anonymous": false}Anonymous user token
1234567{  "iss": "supabase",  "ref": "abcdefghijklmnopqrst",  "role": "anon",  "iat": 1640991600,  "exp": 1640995200}Service role token
1234567{  "iss": "supabase",  "ref": "abcdefghijklmnopqrst",  "role": "service_role",  "iat": 1640991600,  "exp": 1640995200}Language-Specific considerations
Rust
In Rust, the ref field is a reserved keyword. When deserializing JWTs, you'll need to handle this:
123456789101112use serde::{Deserialize, Serialize};#[derive(Debug, Deserialize, Serialize)]struct JwtClaims {    iss: String,    #[serde(rename = "ref")] // Handle reserved keyword    project_ref: Option<String>,    role: String,    iat: i64,    exp: i64,    // ... other claims}TypeScript/JavaScript
12345678910111213141516171819202122interface JwtClaims {  iss: string  aud: string | string[]  exp: number  iat: number  sub: string  role: string  aal: 'aal1' | 'aal2'  session_id: string  email: string  phone: string  is_anonymous: boolean  jti?: string  nbf?: number  app_metadata?: Record<string, any>  user_metadata?: Record<string, any>  amr?: Array<{    method: string    timestamp: number  }>  ref?: string // Only in anon/service role tokens}Python
123456789101112131415161718192021222324252627from typing import Optional, Union, List, Dict, Anyfrom dataclasses import dataclass@dataclassclass AmrEntry:    method: str    timestamp: int@dataclassclass JwtClaims:    iss: str    aud: Union[str, List[str]]    exp: int    iat: int    sub: str    role: str    aal: str    session_id: str    email: str    phone: str    is_anonymous: bool    jti: Optional[str] = None    nbf: Optional[int] = None    app_metadata: Optional[Dict[str, Any]] = None    user_metadata: Optional[Dict[str, Any]] = None    amr: Optional[List[AmrEntry]] = None    ref: Optional[str] = None  # Only in anon/service role tokensGo
123456789101112131415161718192021222324type AmrEntry struct {    Method    string `json:"method"`    Timestamp int64  `json:"timestamp"`}type JwtClaims struct {    Iss         string                 `json:"iss"`    Aud         interface{}            `json:"aud"` // string or []string    Exp         int64                  `json:"exp"`    Iat         int64                  `json:"iat"`    Sub         string                 `json:"sub"`    Role        string                 `json:"role"`    Aal         string                 `json:"aal"`    SessionID   string                 `json:"session_id"`    Email       string                 `json:"email"`    Phone       string                 `json:"phone"`    IsAnonymous bool                   `json:"is_anonymous"`    Jti         *string                `json:"jti,omitempty"`    Nbf         *int64                 `json:"nbf,omitempty"`    AppMetadata map[string]interface{} `json:"app_metadata,omitempty"`    UserMetadata map[string]interface{} `json:"user_metadata,omitempty"`    Amr         []AmrEntry             `json:"amr,omitempty"`    Ref         *string                `json:"ref,omitempty"` // Only in anon/service role tokens}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