new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Supabase · Auth · all subjects

authentication/methods

414 notes in this subject, read out of this brain and free to use. This is page 4 of 7.

SAML attribute mapping: default values

You can specify a default value for an attribute key that may be missing in the SAML assertion. For example: {"keys": {"custom_claim": {"name": "custom_claim", "default": 123}}}.

SAML attribute mapping: multiple names fallback

If a SAML assertion may expose the same attribute under different names for different users, specify multiple names to look up. These are checked in order until a value is found. For example: {"keys": {"custom_claim": {"names": ["first-look-for-this-attribute", "then-this-one"]}}}.

Update SAML identity provider attribute mappings

To change the attribute mappings for an existing SAML provider, use: supabase sso update <provider-uuid> --project-ref <your-project> --attribute-mapping-file /path/to/attribute/mapping.json

Remove SAML identity provider connection

To remove a connection to a SAML identity provider, run: supabase sso remove <provider-id> --project-ref <your-project>. All user accounts from that identity provider will be immediately logged out. User information remains in the system but those accounts cannot be accessed in the future, even if the connection is added again.

List SAML identity providers

To view a list of all registered SAML identity providers, run: supabase sso list --project-ref <your-project>

View detailed SAML provider information

To see all information about a specific SAML provider, run: supabase sso show <provider-id> --project-ref <your-project>. Use the -o json flag to output as JSON.

Update SAML identity provider configuration

You can update SAML provider settings using: supabase sso update <provider-id> --project-ref <your-project>. This is necessary when cryptographic keys are rotated, metadata URLs change, domains change, or attribute mappings change. The unique SAML EntityID cannot be changed; if it changes, the provider must be registered as a new connection.

MCP token validation

When an MCP server makes requests to Supabase APIs on behalf of authenticated users, it sends access tokens issued by Supabase Auth like any other OAuth client. Use the same token validation as other OAuth clients, as documented in the Token Security & RLS guide.

MCP user approval requirements

Always require explicit user approval for MCP clients. Show clear information about what the AI agent can access, display the client name and description, list the scopes being requested, provide an option to deny access, and allow users to revoke access later.

MCP authorization code expiration

Authorization codes issued during MCP token exchange expire after 10 minutes. If a client receives an 'invalid_grant' error during token exchange, verify that the authorization code hasn't expired.

MCP client OAuth registration options

MCP servers have two options for OAuth client setup: (1) Pre-register an OAuth client manually by following the Register an OAuth client guide and use the client credentials in the MCP server. (2) Enable dynamic client registration in Authentication > OAuth Server in the Supabase dashboard to allow MCP clients to register themselves automatically without manual intervention.

MCP OAuth configuration discovery endpoint

MCP clients automatically discover OAuth configuration from the discovery endpoint at https://<project-ref>.supabase.co/.well-known/oauth-authorization-server/auth/v1, where <project-ref> is your project reference ID.

MCP server Supabase Auth configuration URL

To configure an MCP server to use Supabase Auth, use the base URL https://<project-ref>.supabase.co/auth/v1, where <project-ref> is your project reference ID from the Supabase dashboard.

MCP authentication flow steps

When building an MCP server that connects to Supabase, authentication flows through Supabase Auth in five steps: (1) Discovery - The MCP client fetches OAuth configuration from Supabase's discovery endpoint. (2) Registration (optional) - The client registers itself as an OAuth client in the Supabase project. (3) Authorization - User is redirected to the authorization endpoint to approve the AI tool's access. (4) Token exchange - Supabase issues access and refresh tokens for the authenticated user. (5) Authenticated access - The MCP server can make requests to Supabase APIs on behalf of the user.

MCP benefits using Supabase Auth

Using Supabase Auth for MCP provides several benefits: (1) Use existing user base - AI agents authenticate as existing users without creating separate authentication systems. (2) Standards-compliant OAuth 2.1 with PKCE that MCP clients expect. (3) Automatic discovery via Supabase's discovery endpoints. (4) Dynamic client registration allowing automatic MCP client registration. (5) Row Level Security policies automatically apply to MCP clients. (6) User authorization through explicit approval flows. (7) Automatic refresh token rotation and expiration handling.

MCP prerequisites for setup

Before setting up MCP authentication with Supabase, you must: (1) Enable OAuth 2.1 server in the Supabase project. (2) Build an authorization endpoint. (3) Optionally enable dynamic client registration.

MCP redirect URI validation during token exchange

When an MCP client performs token exchange, the redirect URI used must exactly match the redirect URI registered for the OAuth client. Mismatches will cause token exchange to fail.

MCP code verifier matching requirement

During MCP token exchange, if a client receives an 'invalid_grant' error, ensure the code verifier matches the code challenge that was used during the authorization request.

Dynamic registration security considerations

Dynamic registration allows any MCP client to register with the project. Consider: requiring user approval for all clients, monitoring registered clients regularly, and validating redirect URIs are from trusted domains.

OAuth 2.1 grant types supported by Supabase Auth

Supabase Auth supports two OAuth 2.1 grant types: (1) Authorization Code with PKCE (authorization_code) for obtaining initial access tokens, and (2) Refresh Token (refresh_token) for obtaining new access tokens without re-authentication. Other grant types like client_credentials or password are not supported.

PKCE parameters generation for OAuth authorization

Before initiating the authorization code flow, the client must generate PKCE parameters: a code_verifier (43-128 characters generated using crypto.getRandomValues) and a code_challenge (SHA-256 hash of the verifier, base64-URL encoded). The code_verifier must be stored in session storage for later use during token exchange.

Authorization request parameters for OAuth flow

Required parameters for authorization request to https://<project-ref>.supabase.co/auth/v1/oauth/authorize: response_type (must be 'code'), client_id, redirect_uri (must exactly match registered URI), code_challenge, code_challenge_method (must be 'S256'). Optional parameters: state (random string for CSRF protection, highly recommended), scope (space-separated list like 'openid email profile phone', default is 'email'), nonce (random string for replay attack protection, included in ID token if provided).

Authorization code properties and error handling

Authorization codes issued by Supabase Auth are short-lived (valid for 10 minutes), single-use (can only be exchanged once), and bound to PKCE (can only be exchanged with the correct code verifier). If user denies access, Supabase Auth redirects with error parameters: error (e.g. 'access_denied', 'invalid_request', 'server_error'), error_description (human-readable explanation), and state (original state parameter for CSRF protection).

OAuth token endpoint authentication methods

Supabase Auth supports three token_endpoint_auth_methods: (1) 'none' for public clients - send only client_id in request body; (2) 'client_secret_basic' for confidential clients (default) - credentials sent via Authorization header using HTTP Basic authentication with base64-encoded client_id:client_secret; (3) 'client_secret_post' for confidential clients - credentials sent as form parameters (client_id and client_secret) in request body.

Token exchange request for authorization code

To exchange authorization code for tokens, POST to https://<project-ref>.supabase.co/auth/v1/oauth/token with grant_type='authorization_code', code (authorization code), client_id, redirect_uri (must match the one used in authorization request), and code_verifier (the PKCE verifier generated earlier). Client authentication method depends on token_endpoint_auth_method setting.

OAuth token response fields

On successful token exchange, Supabase Auth returns JSON with fields: access_token (JWT for accessing resources), token_type (always 'bearer'), expires_in (token lifetime in seconds, default 3600), refresh_token (for obtaining new access tokens), scope (granted scopes from authorization request), id_token (OpenID Connect ID token, included only if 'openid' scope was requested).

Supported OAuth scopes and defaults

Supported scopes are: 'openid' (enables OpenID Connect and includes ID token in response), 'email' (grants access to email and email_verified claims), 'profile' (grants access to profile information like name and picture), 'phone' (grants access to phone_number and phone_number_verified claims). Default scope when none specified is 'email'. Custom scopes are not currently supported. Scopes affect what information is included in ID tokens and UserInfo endpoint responses.

Refresh token flow for OAuth clients

Clients should refresh access tokens when: (1) access token is expired (check exp claim), (2) access token is about to expire (proactive refresh), or (3) API call returns 401 Unauthorized. POST to https://<project-ref>.supabase.co/auth/v1/oauth/token with grant_type='refresh_token' and refresh_token. Client authentication method depends on token_endpoint_auth_method setting. Response contains new access_token, token_type, expires_in, and optionally a new refresh_token (which should replace the old one as tokens may be rotated).

OpenID Connect ID token requirements

ID tokens are only included in the token response when the 'openid' scope is requested. ID tokens are JWTs that contain user identity information and are signed by Supabase Auth. They are valid for 1 hour. Claims included depend on requested scopes: standard OIDC claims include sub (user ID), nonce (from authorization request if provided), email, email_verified, phone_number, phone_number_verified, name, picture, iss (issuer), aud (client ID), exp (expiration), iat (issued-at), auth_time (authentication time).

OpenID Connect discovery endpoints

Supabase Auth exposes OIDC and OAuth 2.1 discovery endpoints: https://<project-ref>.supabase.co/auth/v1/.well-known/openid-configuration and https://<project-ref>.supabase.co/auth/v1/.well-known/oauth-authorization-server. Both return the same metadata and can be used interchangeably. Metadata includes available endpoints (authorization, token, userinfo, JWKS), supported grant types and response types, supported scopes and claims, and token signing algorithms.

UserInfo endpoint for OAuth clients

Clients can retrieve user information by making a GET/POST request to https://<project-ref>.supabase.co/auth/v1/oauth/userinfo with Authorization header 'Bearer <access-token>'. Information returned depends on granted scopes. With 'email' scope: sub, email, email_verified. With 'email profile phone' scopes: sub, email, email_verified, phone_number, phone_number_verified, name, picture.

User grant management for OAuth applications

Users can view and manage OAuth applications they've authorized using supabase.auth.oauth.getUserGrants() which returns list of grants with: id (grant UUID), client_id, client_name, scopes (array of granted scopes), created_at, updated_at. Users can revoke access for specific OAuth client using supabase.auth.oauth.revokeGrant(clientId). When access is revoked, all refresh tokens for that client are deleted and user must re-authorize to grant access again.

Authorization path workflow for OAuth consent

During OAuth authorization, Supabase Auth redirects user to configured authorization path (e.g. https://example.com/oauth/consent?authorization_id=<id>). Your frontend at this path should: (1) Extract authorization_id from query parameters, (2) Call supabase.auth.oauth.getAuthorizationDetails(authorization_id) to fetch OAuth client info and request parameters, (3) Check user authentication and redirect to login if needed (preserving authorization_id), (4) Display consent screen with client info/scopes, (5) Handle user decision by calling supabase.auth.oauth.approveAuthorization(authorization_id) or denyAuthorization(authorization_id), then redirect to returned redirect_url.

PKCE code verifier generation example

Example JavaScript code for PKCE parameter generation: function generateCodeVerifier() { const array = new Uint8Array(32) crypto.getRandomValues(array) return base64URLEncode(array) } async function generateCodeChallenge(verifier) { const encoder = new TextEncoder() const data = encoder.encode(verifier) const hash = await crypto.subtle.digest('SHA-256', data) return base64URLEncode(new Uint8Array(hash)) } function base64URLEncode(buffer) { return btoa(String.fromCharCode(...buffer)) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, '') } const codeVerifier = generateCodeVerifier() sessionStorage.setItem('code_verifier', codeVerifier) const codeChallenge = await generateCodeChallenge(codeVerifier)

Public client token exchange example

Example JavaScript code for token exchange by public client (token_endpoint_auth_method: none): const codeVerifier = sessionStorage.getItem('code_verifier') const response = await fetch(`https://<project-ref>.supabase.co/auth/v1/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'authorization_code', code: authorizationCode, client_id: '<client-id>', redirect_uri: '<redirect-uri>', code_verifier: codeVerifier, }), }) const tokens = await response.json()

Confidential client token exchange with POST auth example

Example JavaScript code for token exchange by confidential client using POST parameters (token_endpoint_auth_method: client_secret_post): const codeVerifier = sessionStorage.getItem('code_verifier') const response = await fetch(`https://<project-ref>.supabase.co/auth/v1/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'authorization_code', code: authorizationCode, client_id: '<client-id>', client_secret: '<client-secret>', redirect_uri: '<redirect-uri>', code_verifier: codeVerifier, }), }) const tokens = await response.json()

Public client refresh token example

Example JavaScript code for refreshing access token as public client (token_endpoint_auth_method: none): async function refreshAccessToken(refreshToken) { const response = await fetch(`https://<project-ref>.supabase.co/auth/v1/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, client_id: '<client-id>', }), }) if (!response.ok) { throw new Error('Failed to refresh token') } return await response.json() }

Confidential client refresh token example

Example JavaScript code for refreshing access token as confidential client using HTTP Basic auth (token_endpoint_auth_method: client_secret_basic): async function refreshAccessTokenConfidential(refreshToken) { const response = await fetch(`https://<project-ref>.supabase.co/auth/v1/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: 'Basic ' + btoa('<client-id>:<client-secret>'), }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, }), }) if (!response.ok) { throw new Error('Failed to refresh token') } return await response.json() }

OAuth flow authorization code step sequence

OAuth authorization code flow step sequence: (1) Client generates PKCE parameters (code_verifier, code_challenge), (2) Client redirects user to /oauth/authorize with code_challenge, (3) Supabase Auth validates params and redirects to authorization_path, (4) Frontend calls getAuthorizationDetails() to get client info, (5) User logs in and views consent screen, (6) Frontend calls approveAuthorization() to approve, (7) Supabase Auth redirects back to client callback with code, (8) Client exchanges code for tokens via POST /oauth/token with code_verifier, (9) Supabase Auth returns access_token, refresh_token, id_token, (10) Client uses access_token for resource access, (11) Client refreshes tokens via POST /oauth/token with refresh_token when needed.

List passkeys JavaScript example

To list the current user's passkeys in JavaScript: const { data: passkeys } = await supabase.auth.passkey.list() // Returns array like: [{ id, friendly_name, created_at, last_used_at? }, ...]

Rename passkey JavaScript example

To rename a passkey in JavaScript: await supabase.auth.passkey.update({ passkeyId: passkeys[0].id, friendlyName: 'Work laptop', })

Delete passkey JavaScript example

To delete a passkey in JavaScript: await supabase.auth.passkey.delete({ passkeyId: passkeys[0].id })

List passkeys Dart example

To list the current user's passkeys in Dart: final List<Passkey> passkeys = await supabase.auth.passkey.list();

Rename passkey Dart example

To rename a passkey in Dart: await supabase.auth.passkey.update( passkeyId: passkeys.first.id, friendlyName: 'Work laptop', );

Delete passkey Dart example

To delete a passkey in Dart: await supabase.auth.passkey.delete(passkeyId: passkeys.first.id);

List passkeys Swift example

To list the current user's passkeys in Swift: let passkeys: [PasskeyListItem] = try await supabase.auth.listPasskeys()

Rename passkey Swift example

To rename a passkey in Swift: let updated = try await supabase.auth.renamePasskey( id: passkeys.first!.id, friendlyName: "Work laptop" )

Delete passkey Swift example

To delete a passkey in Swift: try await supabase.auth.deletePasskey(id: passkeys.first!.id)

Passkey friendly name character limit

The friendlyName for a passkey is limited to 120 characters.

Passkey last used timestamp

lastUsedAt is updated each time the passkey is used to sign in.

Admin API for passkey management JavaScript

To manage passkeys from a trusted server in JavaScript using the admin API: import { createClient } from '@supabase/supabase-js' const supabase = createClient(supabaseUrl, supabaseSecretKey, { auth: { experimental: { passkey: true } }, }) const { data } = await supabase.auth.admin.passkey.listPasskeys({ userId }) await supabase.auth.admin.passkey.deletePasskey({ userId, passkeyId })

Admin API for passkey management Dart

To manage passkeys from a trusted server in Dart using the admin API: final supabase = SupabaseClient(supabaseUrl, secretKey); final List<Passkey> passkeys = await supabase.auth.admin.passkey.listPasskeys( userId: userId, ); await supabase.auth.admin.passkey.deletePasskey( userId: userId, passkeyId: passkeyId, );

Passkey error code: passkey_disabled

Error code passkey_disabled means passkey sign-in is not enabled for this project.

Passkey error code: too_many_passkeys

Error code too_many_passkeys means the user has reached the maximum number of passkeys allowed per account.

Passkey error code: webauthn_credential_exists

Error code webauthn_credential_exists means this authenticator has already been registered to the account.

Passkey error code: webauthn_credential_not_found

Error code webauthn_credential_not_found means the credential in the assertion is not registered with Supabase Auth.

Passkey error code: webauthn_challenge_not_found

Error code webauthn_challenge_not_found means the challenge ID is unknown or has already been consumed.

Passkey limitation: Anonymous users cannot register

Anonymous users cannot register passkeys — link an email or phone first.

Passkey error code: webauthn_challenge_expired

Error code webauthn_challenge_expired means the challenge expired before the client returned a credential.

Passkey error code: webauthn_verification_failed

Error code webauthn_verification_failed means the signature, attestation, or assertion did not validate against the challenge.

Give your agent this brain