Password security minimum requirements recommendation
Passwords are more secure when they are longer and use a larger set of characters. The minimum recommended password length is 8 characters. Using a larger character set (digits, lowercase letters, uppercase letters, and symbols) significantly increases the number of guesses required to brute-force an account.
Password character complexity and guess attempts required
The minimum number of guesses required to access an account varies by character set and length: digits only (8 chars) requires ~2^27 guesses; digits and letters (8 chars) requires ~2^41 guesses; digits, lowercase and uppercase letters (8 chars) requires ~2^48 guesses; digits, lowercase and uppercase letters, and symbols (8 chars) requires ~2^52 guesses.
Allowed symbols in password requirements
When requiring symbols in passwords, the allowed symbols are: !@#$%^&*()_+-=[]{};'\:"|<>?,./`~
Supabase Auth password strength configuration options
Supabase Auth allows fine-grained control over password strength through the Auth settings. Administrators can set a minimum password length (8 characters or more is recommended), require specific characters that must appear at least once (digits, lowercase and uppercase letters, and/or symbols), and prevent use of leaked passwords using the HaveIBeenPwned.org Pwned Passwords API.
Leaked password protection availability
Supabase Auth's leaked password protection feature using the HaveIBeenPwned.org Pwned Passwords API is available on the Pro Plan and above.
Reauthentication requirement for password changes
When reauthentication is required for password changes, users who have not been logged in within the last 24 hours must reauthenticate before changing their password. A nonce is sent to the user during the reauthentication process, and this nonce must be validated and included in the password change request. When reauthentication is disabled, users can change their password at any time.
Reauthentication flow with nonce for password change
The reauthentication flow involves calling supabase.auth.reauthenticate() to obtain a nonce, then sending that nonce with the password change in the updateUser() call with the nonce parameter.
Current password verification for password changes
Supabase Auth can be configured to require users to supply their current password when changing their password. When this setting is enabled, the password change request validates that the current password is correct before updating to the new password.
Current password verification API usage
To change a password with current password verification, include the current_password parameter in the supabase.auth.updateUser() call along with the new password.
Password hashing algorithm used by Supabase Auth
Supabase Auth uses bcrypt, a strong password hashing function, to store hashes of users' passwords. Only hashed passwords are stored; actual passwords are never stored. Each hash is accompanied by a randomly generated salt parameter for extra security. The hash is stored in the encrypted_password column of the auth.users table.
Password strength requirement impact on existing users
When password strength requirements are strengthened, existing users can still sign in with their current password even if it doesn't meet the new requirements. However, if a user's password falls short of updated standards, they will encounter a WeakPasswordError during the signInWithPassword process. This applies to new users and existing users changing their passwords, ensuring everyone adheres to enhanced security standards.
OAuth access token structure and claims
OAuth access tokens issued by Supabase Auth are JWTs. Every OAuth access token includes: sub (user-uuid), role (authenticated), aud (authenticated), user_id (user-uuid), email (user@example.com), client_id (unique identifier of the OAuth client), aal (aal1), amr (array with method and timestamp), session_id, iss (issuer URL), iat (issued at timestamp), exp (expiration timestamp). The key OAuth-specific claim is client_id, which uniquely identifies the OAuth client that obtained the token.
Custom Access Token Hooks work with OAuth tokens
Custom Access Token Hooks are triggered for all token issuance and work with OAuth tokens. Use client_id or authentication_method (oauth_provider/authorization_code for OAuth flows) to differentiate OAuth from regular authentication. This allows you to inject custom claims based on the OAuth client and customize standard JWT claims like audience (aud) or add client-specific metadata.
Custom Access Token Hook: Customize audience claim for OAuth clients
Example Deno hook that customizes the audience claim for different OAuth clients: Deno.serve(async (req) => { const { user, claims, client_id } = await req.json(); if (client_id === 'mobile-app-client-id') { return new Response(JSON.stringify({ claims: { aud: 'https://api.myapp.com', app_version: '2.0.0' } }), { headers: { 'Content-Type': 'application/json' } }); } if (client_id === 'analytics-partner-id') { return new Response(JSON.stringify({ claims: { aud: 'https://analytics.partner.com', access_level: 'read-only' } }), { headers: { 'Content-Type': 'application/json' } }); } return new Response(JSON.stringify({ claims: {} }), { headers: { 'Content-Type': 'application/json' } }); });
Audience claim importance for third parties
The audience (aud) claim is especially important for: JWT validation by third parties (services can verify tokens were issued for their specific API), multi-tenant applications (different audiences for different client applications), and compliance (meeting security requirements that mandate audience validation).
Custom Access Token Hook: Add client-specific claims
Example showing how to add custom claims and metadata based on OAuth client. For mobile-app-client-id: set aud to 'https://mobile.myapp.com', app_version to '2.0.0', platform to 'mobile'. For analytics-client-id: set aud to 'https://analytics.myapp.com', read_only to true, data_retention_days to 90. For clients starting with 'mcp-' (MCP AI agents): query approved_ai_agents table and set aud to 'https://mcp.myapp.com/{client_id}', ai_agent to true, agent_name from database, max_retention from database.
@supabase/ssr package for server-side auth in Next.js
The `@supabase/ssr` package provides Server-Side Auth functionality for Next.js and configures Supabase to use cookies for storing user sessions. Install with `npm install @supabase/ssr`. Read the Next.js Server-Side Auth guide for more information.
Next.js middleware for Auth token refresh with proxy
Next.js Server Components cannot write cookies directly, so a proxy middleware is needed to refresh expired Auth tokens. The middleware should: refresh the Auth token with `supabase.auth.getClaims`, pass the refreshed token to Server Components through `request.cookies.set`, and pass the refreshed token to the browser through `response.cookies.set` to replace the old token. Create a `proxy.ts` file at the project root following Next.js conventions.
Caution: user session from cookies can be spoofed
Be careful when protecting pages in Next.js. The server gets the user session from cookies, which anyone can spoof. This requires careful validation on the server side.
Email template configuration for server-side auth with token_hash
To support server-side authentication flow with token hashing in Next.js: go to the Auth templates page in the dashboard, select the Confirm signup template, and change `{{ .ConfirmationURL }}` to `{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email`. This allows the server endpoint to exchange the token_hash for a session.
Server-side confirmation endpoint for token_hash exchange
In a Next.js SSR environment, create a server endpoint (typically at `app/auth/confirm/route.ts`) that: retrieves the token_hash from query parameters, exchanges this code for a session using Supabase auth, stores the session in cookies, and redirects the user to the account page.
Magic Links for passwordless email authentication
Supabase supports Magic Links as an authentication method that allows users to sign in with their email without using passwords. The user receives a confirmation email with a magic link.
Temporary access overview and prerequisites
Temporary access enables short-lived database connections tied to a Supabase user via Personal Access Token (PAT) or dashboard session JWT. It is disabled by default. Projects must be on Postgres 17.6.1.081 or higher to enable this feature. Temporary access only applies to direct Postgres and Supavisor connection pooler connections; HTTP APIs (PostgREST, Storage, Auth) require service-specific authentication tokens.
Enable temporary access via Management API
Use the Management API endpoint PUT https://api.supabase.com/v1/projects/{PROJECT_REF}/database/jit-access with Authorization header containing the management API token and Content-Type application/json. Send JSON body with field 'state' set to either 'enabled' or 'disabled'. To check current status, use GET https://api.supabase.com/v1/projects/{PROJECT_REF}/database/jit-access.
User authorization for temporary access
Once temporary access is enabled, project users must be authorized and mapped to specific Postgres roles. Each user can be authorized to assume one or more Postgres roles. When authorized, the user's Personal Access Token is used as the password for the Postgres role. Existing Postgres role passwords continue to work for long-lived service connections.
Temporary access restrictions via Management API
Restrictions can be applied through Management API endpoint PUT https://api.supabase.com/v1/projects/{PROJECT_REF}/database/jit with parameters: user_id (the gotrue_id of the user), user_roles array containing objects with fields: role (Postgres role name), allowed_networks object with allowed_cidrs array containing cidr strings (IPv4 and/or IPv6 ranges), and expires_at (Unix timestamp in milliseconds). After expiration, database rejects connection even if access token is still valid.
Temporary access connection string usage
To connect using temporary access, use existing connection strings but change the password to the user's Personal Access Token or dashboard token. Example: psql 'postgres://postgres:sbp••••••cc@db.{project-ref}.supabase.co/postgres'. API tokens can be generated for services and configured with expiry times.
Temporary access with connection pooler
Direct connections and IPv4 connection pooler are fully supported for temporary access. IPv6 Transaction pooler (PgBouncer) is not supported. When connecting via the shared connection pooler, add a connection option 'jit=true' either in the URI with options parameter or as conninfo string: psql 'postgres://postgres.{project-ref}:•••••@aws-1-us-west-1.pooler.supabase.com:5432/postgres?options=-c%20jit%3dtrue' or psql "host=aws-1-us-west-1.pooler.supabase.com user=postgres.{project-ref} options='-c jit=true'"