Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ export const auth = {
{ name: 'Rate Limits', url: '/guides/auth/rate-limits' },
{ name: 'Bot Detection (CAPTCHA)', url: '/guides/auth/auth-captcha' },
{ name: 'JWTs', url: '/guides/auth/jwts' },
{ name: 'JWT Fields Reference', url: '/guides/auth/jwt-fields' },
{ name: 'Row Level Security', url: '/guides/database/postgres/row-level-security' },
{
name: 'Column Level Security',
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/guides/auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Authentication and authorization are the core responsibilities of any Auth syste
- **Authentication** means checking that a user is who they say they are.
- **Authorization** means checking what resources a user is allowed to access.

Supabase Auth uses [JSON Web Tokens (JWTs)](/docs/guides/auth/jwts) for authentication. Auth integrates with Supabase's database features, making it easy to use [Row Level Security (RLS)](/docs/guides/database/postgres/row-level-security) for authorization.
Supabase Auth uses [JSON Web Tokens (JWTs)](/docs/guides/auth/jwts) for authentication. For a complete reference of all JWT fields, see the [JWT Fields Reference](/docs/guides/auth/jwt-fields). Auth integrates with Supabase's database features, making it easy to use [Row Level Security (RLS)](/docs/guides/database/postgres/row-level-security) for authorization.

## The Supabase ecosystem

Expand Down
288 changes: 288 additions & 0 deletions apps/docs/content/guides/auth/jwt-fields.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
---
id: 'jwt-fields'
title: 'JWT Fields Reference'
subtitle: 'Complete reference for JWT fields in Supabase'
---

This page provides a comprehensive reference for all JWT fields 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 | `"[email protected]"` |
| `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 fields

| 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

```json
{
"aal": "aal1",
"amr": [
{
"method": "password",
"timestamp": 1640991600
}
],
"app_metadata": {
"provider": "email",
"providers": ["email"]
},
"aud": "authenticated",
"email": "[email protected]",
"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

```json
{
"iss": "supabase",
"ref": "abcdefghijklmnopqrst",
"role": "anon",
"iat": 1640991600,
"exp": 1640995200
}
```

### Service role token

```json
{
"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:

```rust
use 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 fields
}
```

### TypeScript/JavaScript

```typescript
interface 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

```python
from typing import Optional, Union, List, Dict, Any
from dataclasses import dataclass

@dataclass
class AmrEntry:
method: str
timestamp: int

@dataclass
class 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 tokens
```

### Go

```go
type 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:

1. **Check Required Fields**: Ensure all required claims are present
2. **Validate Types**: Verify field types match expected types
3. **Check Expiration**: Validate `exp` timestamp is in the future
4. **Verify Issuer**: Ensure `iss` matches your Supabase project
5. **Check Audience**: Validate `aud` matches expected audience
6. **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

## Related documentation

- [JWT Overview](/docs/guides/auth/jwts)
- [Custom Access Token Hooks](/docs/guides/auth/auth-hooks/custom-access-token-hook)
- [Row Level Security](/docs/guides/database/postgres/row-level-security)
- [Server-Side Auth](/docs/guides/auth/server-side)
1 change: 1 addition & 0 deletions apps/docs/content/guides/auth/jwts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,4 @@ Now that you understand what JWTs are and where they're used in Supabase, you ca
## Resources

- JWT debugger: https://jwt.io/
- [JWT Fields Reference](/docs/guides/auth/jwt-fields) - Complete reference for all JWT fields in Supabase
64 changes: 63 additions & 1 deletion apps/docs/content/guides/getting-started/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP)
- [Cline](#cline) (VS Code extension)
- [Claude desktop](#claude-desktop)
- [Claude code](#claude-code)
- [Qodo Gen](#qodo-gen)
- [Amp](#amp)

Once connected, your AI assistants can interact with and query your Supabase projects on your behalf.

Expand Down Expand Up @@ -123,6 +123,68 @@ You can also add the Supabase MCP server as a locally-scoped server, which will

Locally-scoped servers take precedence over project-scoped servers with the same name and are stored in your project-specific user settings.

### Amp

You can add the Supabase MCP server to Amp in two ways:

#### Option 1: VSCode settings.json

1. Open "Preferences: Open User Settings (JSON)"
2. Add the following configuration:

```json
{
"amp.mcpServers": {
"supabase": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--read-only",
"--project-ref=<project-ref>"
],
"env": {
"SUPABASE_ACCESS_TOKEN": "<personal-access-token>"
}
}
}
}
```

Replace `project-ref` and `personal-access-token` with your project ref and personal access token.

3. Save the configuration file.
4. Restart VS Code to apply the new configuration.

#### Option 2: Amp CLI

1. Edit `~/.config/amp/settings.json`
1. Add the following configuration:

```json
{
"amp.mcpServers": {
"supabase": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--read-only",
"--project-ref=<project-ref>"
],
"env": {
"SUPABASE_ACCESS_TOKEN": "<personal-access-token>"
}
}
}
}
```

Replace `project-ref` and `personal-access-token` with your project ref and personal access token.

1. Save the configuration file.
1. Restart Amp to apply the new configuration.

### Qodo Gen

1. Open [Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen) chat panel in VSCode or IntelliJ.
Expand Down
Loading