Custom SAML attribute mapping example
Example custom attribute mapping for IdP-specific attributes: {"attribute_mapping": {"keys": {"email": {"name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"}, "name": {"name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"}, "department": {"name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/department", "default": "unknown"}, "groups": {"name": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups", "array": true}, "role": {"names": ["http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "role", "Role"], "default": "member"}}}}. Each mapping key supports: name (primary SAML attribute name), names (array of fallback attribute names), default (value if attribute missing), array (set to true for multi-valued attributes).
SAML attribute mapping default user ID detection
If no attribute mapping is provided, Auth uses this default user ID detection order: (1) urn:oasis:names:tc:SAML:attribute:subject-id attribute, (2) Subject NameID if format is persistent.
SERVICE_ROLE_KEY requirement for SAML admin API
SERVICE_ROLE_KEY from the .env file is required for all admin API calls related to SAML provider registration, management, and deletion. It must be passed in both Authorization Bearer header and apikey header.
SAML attribute mapping default email detection order
If no attribute mapping is provided, Auth uses this default email detection order: (1) urn:oid:0.9.2342.19200300.100.1.3 (LDAP mail OID), (2) http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress, (3) http://schemas.xmlsoap.org/claims/EmailAddress, (4) attributes named mail, Mail, or email, (5) Subject NameID if it looks like an email address.
IdP-specific SAML configuration for Auth0
For Auth0 SAML setup: create a Regular Web Application, copy the SAML Metadata URL from the Advanced Settings Endpoints tab (this is the IdP metadata URL for Supabase), enable the SAML2 Web App add-on in Advanced Settings, set Application Callback URL (ACS) to {API_EXTERNAL_URL}/sso/saml/acs in the add-on settings, enable the add-on.
IdP-specific SAML configuration for Google Workspace
For Google Workspace SAML setup: in Admin console go to Apps > Web and mobile apps > Add custom SAML app, set ACS URL to {API_EXTERNAL_URL}/sso/saml/acs, set Entity ID to {API_EXTERNAL_URL}/sso/saml/metadata, set Name ID format to PERSISTENT.
IdP-specific SAML configuration for Azure AD
For Azure AD (Entra ID) SAML setup: create an Enterprise Application as a non-gallery application, set up single sign-on via SAML, set Identifier (Entity ID) to {API_EXTERNAL_URL}/sso/saml/metadata, set Reply URL (ACS) to {API_EXTERNAL_URL}/sso/saml/acs, use the App Federation Metadata URL from the SAML Signing Certificate section as the metadata URL for Auth.
IdP-specific SAML configuration for Okta
For Okta SAML setup: create a SAML 2.0 application, set Single Sign-On URL to {API_EXTERNAL_URL}/sso/saml/acs, set Audience URI (SP Entity ID) to {API_EXTERNAL_URL}/sso/saml/metadata, leave Default RelayState blank, set Name ID format to Persistent.
SAML IdP response after registration
After successfully registering a SAML IdP via the admin API, the response includes: id (UUID for the provider), resource_id (null unless custom), disabled (false by default), saml object (contains entity_id and metadata_url), domains array (email domains associated), created_at, updated_at.
SAML IdP registration parameters reference
SAML IdP registration parameters: type (required, must be "saml"), metadata_url (one of these, HTTPS URL to IdP metadata with auto-refresh), metadata_xml (one of these, raw IdP metadata XML string), domains (no, array of email domains for domain-based SSO lookup), attribute_mapping (no, map SAML attributes to user claims), name_id_format (no, request specific NameID format: persistent, emailAddress, transient, or unspecified), resource_id (no, custom external identifier), disabled (no, set to true to register but disable).
Service provider metadata values in self-hosted Supabase
The SAML service provider metadata contains: Entity ID = {API_EXTERNAL_URL}/sso/saml/metadata; ACS URL = {API_EXTERNAL_URL}/sso/saml/acs; NameID formats = persistent, emailAddress; Signing certificate = derived from SAML_PRIVATE_KEY.
SAML service provider metadata endpoint
Once SAML is enabled, Supabase exposes service provider metadata at {API_EXTERNAL_URL}/sso/saml/metadata. The metadata can be retrieved via curl at http://<your-domain>/auth/v1/sso/saml/metadata. Add ?download=true to the request URL to get the metadata as a downloadable XML file with a 5-year validity period. The metadata contains the Entity ID, ACS endpoint URL, NameID formats (persistent and emailAddress), and signing certificate.
SITE_URL and ADDITIONAL_REDIRECT_URLS for OAuth redirect
After successful OAuth login, the Auth service redirects to SITE_URL or a URL from ADDITIONAL_REDIRECT_URLS. Ensure SITE_URL in .env is set to the application's URL. If the app uses a different redirect URL, add it to ADDITIONAL_REDIRECT_URLS (comma-separated).
OAuth callback URL format for self-hosted Supabase
The OAuth callback URL for a self-hosted Supabase instance must be in the format: https://<your-domain>/auth/v1/callback. This URL must be registered with each OAuth provider.
API_EXTERNAL_URL requirement for self-hosted OAuth
The API_EXTERNAL_URL must be set to the publicly reachable URL of the Supabase instance (e.g., https://<your-domain>/auth/v1). This is required before configuring OAuth providers.
HTTPS requirement for OAuth providers
HTTPS is required by most OAuth providers. HTTP callback URLs are rejected except for localhost. This applies to all self-hosted Supabase OAuth configurations.
OAuth request flow in self-hosted Supabase
The OAuth flow in self-hosted Supabase proceeds as follows: 1) App calls supabase.auth.signInWithOAuth() and browser redirects to Auth service. 2) API gateway routes request to Auth container (/auth/v1/authorize). 3) Auth redirects user to OAuth provider (e.g., Google) for consent. 4) Provider redirects back to https://<your-domain>/auth/v1/callback. 5) Auth exchanges authorization code for tokens and redirects user to SITE_URL or an allowed redirect URL.
GoTrue OAuth environment variable naming pattern
The Auth service (GoTrue) uses the prefix GOTRUE_EXTERNAL_ followed by a provider name for all OAuth configuration. For example, for Google: GOTRUE_EXTERNAL_GOOGLE_ENABLED, GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID, GOTRUE_EXTERNAL_GOOGLE_SECRET, GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI.
Self-hosted OAuth configuration steps
To configure OAuth for self-hosted Supabase: 1) Register your app with the OAuth provider and set the authorized redirect URL to https://<your-domain>/auth/v1/callback. 2) Copy client ID and client secret into .env file with provider prefix (e.g., GOOGLE_CLIENT_ID, GOOGLE_SECRET). 3) Uncomment the corresponding GOTRUE_EXTERNAL_* lines in docker-compose.yml auth service environment. 4) Restart the auth service with: sh run.sh recreate auth. 5) Verify with: curl -H 'apikey: your-anon-key' https://<your-domain>/auth/v1/settings
Google OAuth configuration for self-hosted Supabase
To set up Google OAuth for self-hosted Supabase: 1) Go to Google Cloud Console and create or select a project. 2) Navigate to APIs & Services > OAuth consent screen and configure an External app. 3) Go to APIs & Services > Credentials and create OAuth client ID. 4) Set application type to Web application. 5) Add authorized redirect URI: https://<your-domain>/auth/v1/callback. 6) Copy the client ID and secret. In .env, set: GOOGLE_ENABLED=true, GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com, GOOGLE_SECRET=your-google-client-secret. In docker-compose.yml, set: GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}, GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}, GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_SECRET}, GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: ${API_EXTERNAL_URL}/callback
GitHub OAuth configuration for self-hosted Supabase
To set up GitHub OAuth for self-hosted Supabase: 1) Go to GitHub Developer Settings and click New OAuth app. 2) Fill in Homepage URL (e.g., https://<your-domain>). 3) Set Authorization callback URL to https://<your-domain>/auth/v1/callback. 4) Click Register application and copy client ID. 5) Generate and copy a client secret. In .env, set: GITHUB_ENABLED=true, GITHUB_CLIENT_ID=your-github-client-id, GITHUB_SECRET=your-github-client-secret. In docker-compose.yml, set: GOTRUE_EXTERNAL_GITHUB_ENABLED: ${GITHUB_ENABLED}, GOTRUE_EXTERNAL_GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}, GOTRUE_EXTERNAL_GITHUB_SECRET: ${GITHUB_SECRET}, GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI: ${API_EXTERNAL_URL}/callback
Azure (Microsoft) OAuth configuration for self-hosted Supabase
To set up Azure OAuth for self-hosted Supabase: 1) Go to Azure Portal and navigate to All services > Identity > App registrations. 2) Click New registration and add application Name. 3) Under Redirect URI, select Web and enter: https://<your-domain>/auth/v1/callback. 4) Click Register and copy the Application (client) ID. 5) Click Client credentials > Add a certificate or secret, then New client secret. 6) Copy the secret value. In .env, set: AZURE_ENABLED=true, AZURE_CLIENT_ID=your-azure-application-client-id, AZURE_SECRET=your-azure-client-secret. Optionally restrict to a specific tenant with AZURE_URL=https://login.microsoftonline.com/your-tenant-id. In docker-compose.yml, set: GOTRUE_EXTERNAL_AZURE_ENABLED: ${AZURE_ENABLED}, GOTRUE_EXTERNAL_AZURE_CLIENT_ID: ${AZURE_CLIENT_ID}, GOTRUE_EXTERNAL_AZURE_SECRET: ${AZURE_SECRET}, GOTRUE_EXTERNAL_AZURE_REDIRECT_URI: ${API_EXTERNAL_URL}/callback, and optionally GOTRUE_EXTERNAL_AZURE_URL: ${AZURE_URL}
Apple OAuth configuration for self-hosted Supabase
To set up Apple OAuth for self-hosted Supabase: 1) Refer to Apple Developer documentation to enable App ID and create a Services ID. 2) Create a private key for sign in with Apple. 3) Generate a client secret JWT from the private key (see Apple Developer documentation). In .env, set: APPLE_ENABLED=true, APPLE_CLIENT_ID=com.example.your-services-id, APPLE_SECRET=your-generated-jwt-client-secret. In docker-compose.yml, set: GOTRUE_EXTERNAL_APPLE_ENABLED: ${APPLE_ENABLED}, GOTRUE_EXTERNAL_APPLE_CLIENT_ID: ${APPLE_CLIENT_ID}, GOTRUE_EXTERNAL_APPLE_SECRET: ${APPLE_SECRET}, GOTRUE_EXTERNAL_APPLE_REDIRECT_URI: ${API_EXTERNAL_URL}/callback. Apple uses response_mode=form_post for its OAuth flow, which the Auth service handles automatically.
Keycloak OIDC configuration for self-hosted Supabase
To set up Keycloak OIDC for self-hosted Supabase: 1) Open Keycloak admin console and select or create a realm. 2) Go to Clients > Create client and set Client type to OpenID Connect. 3) Set Client ID (e.g., 'supabase'). 4) On next screen, enable Client authentication. 5) Under Valid redirect URIs, add: https://<your-domain>/auth/v1/callback. 6) Save and go to Credentials tab to copy Client secret. In .env, set: KEYCLOAK_ENABLED=true, KEYCLOAK_CLIENT_ID=supabase, KEYCLOAK_SECRET=your-keycloak-client-secret, KEYCLOAK_URL=https://keycloak.example.com/realms/myrealm. The KEYCLOAK_URL is required and must be the full realm URL. In docker-compose.yml, set: GOTRUE_EXTERNAL_KEYCLOAK_ENABLED: ${KEYCLOAK_ENABLED}, GOTRUE_EXTERNAL_KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID}, GOTRUE_EXTERNAL_KEYCLOAK_SECRET: ${KEYCLOAK_SECRET}, GOTRUE_EXTERNAL_KEYCLOAK_REDIRECT_URI: ${API_EXTERNAL_URL}/callback, GOTRUE_EXTERNAL_KEYCLOAK_URL: ${KEYCLOAK_URL}
Supported OAuth providers in Supabase
Supabase Auth supports the following OAuth providers with their environment variable prefixes and additional variables:
Provider | Env prefix | Additional variables | Docs
Apple | APPLE_ | - | Login with Apple
Azure (Microsoft) | AZURE_ | URL (tenant URL) | Login with Azure
Bitbucket | BITBUCKET_ | - | Login with Bitbucket
Discord | DISCORD_ | - | Login with Discord
Facebook | FACEBOOK_ | - | Login with Facebook
Figma | FIGMA_ | - | Login with Figma
GitHub | GITHUB_ | URL (for GitHub Enterprise) | Login with GitHub
GitLab | GITLAB_ | URL (for self-hosted GitLab) | Login with GitLab
Google | GOOGLE_ | - | Login with Google
Kakao | KAKAO_ | - | Login with Kakao
Keycloak (OIDC) | KEYCLOAK_ | URL (realm URL, required) | Login with Keycloak
LinkedIn (OIDC) | LINKEDIN_OIDC_ | - | Login with LinkedIn
Notion | NOTION_ | - | Login with Notion
Slack (OIDC) | SLACK_OIDC_ | - | Login with Slack
Snapchat | SNAPCHAT_ | - | -
Spotify | SPOTIFY_ | - | Login with Spotify
Twitch | TWITCH_ | - | Login with Twitch
Twitter | TWITTER_ | - | Login with Twitter
WorkOS | WORKOS_ | - | Login with WorkOS
Zoom | ZOOM_ | - | Login with Zoom
OAuth provider environment variable requirements
For each OAuth provider configured in self-hosted Supabase, the minimum required environment variables are: ENABLED (true/false), CLIENT_ID, SECRET, and REDIRECT_URI. All must be set in .env and passed through in docker-compose.yml.
LinkedIn OIDC and Slack OIDC multi-word env prefixes
LinkedIn (OIDC) and Slack (OIDC) use multi-word environment variable prefixes. The full Docker Compose variables are GOTRUE_EXTERNAL_LINKEDIN_OIDC_CLIENT_ID and GOTRUE_EXTERNAL_SLACK_OIDC_CLIENT_ID respectively, not LINKEDIN_CLIENT_ID or SLACK_CLIENT_ID.
Environment variables must have matching passthrough in docker-compose.yml
Configuration variables defined in .env are not automatically available inside the container unless there is a matching passthrough definition in docker-compose.yml (e.g., GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${GOOGLE_ENABLED}). Check with 'sh run.sh printenv auth | grep GOTRUE_EXTERNAL' to verify variables are reaching the container.
Verify OAuth provider configuration in self-hosted Supabase
To verify that an OAuth provider is correctly enabled in self-hosted Supabase, run: curl -H 'apikey: your-anon-key' https://<your-domain>/auth/v1/settings. The response should include the provider under 'external', for example: {"external": {"google": true}}
Restart auth service after OAuth configuration
After adding or modifying OAuth configuration in .env and docker-compose.yml for self-hosted Supabase, restart the auth service with: sh run.sh recreate auth
Testing OAuth flow with HTML test page
To test OAuth in self-hosted Supabase: Save this code to index.html, start a Python HTTP server on port 3000 (python -m http.server 3000), ensure SITE_URL in .env is http://localhost:3000, then open http://localhost:3000 in your browser. Example code:
<!doctype html>
<html>
<body>
<h1>Supabase OAuth Test</h1>
<button id="loginBtn">Sign in with Google</button>
<pre id="result"></pre>
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const SUPABASE_URL = 'https://<your-domain>'
const SUPABASE_ANON_KEY = 'your-anon-key'
const supabase = window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY)
const button = document.getElementById('loginBtn')
button.addEventListener('click', async () => {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
})
if (error) {
document.getElementById('result').textContent = JSON.stringify(error, null, 2)
}
})
supabase.auth.getSession().then(({ data }) => {
if (data.session) {
document.getElementById('result').textContent =
'Logged in as: ' + data.session.user.email
}
})
})
</script>
</body>
</html>
Troubleshoot 'Provider not enabled' error in self-hosted OAuth
If receiving 'Provider not enabled' error or provider appears as false in settings: Check that GOTRUE_EXTERNAL_*_ENABLED is set to true in docker-compose.yml. Verify the .env variable is not empty by running: sh run.sh printenv auth | grep GOOGLE (replace GOOGLE with provider name).
GOTRUE_EXTERNAL_SKIP_NONCE_CHECK for mobile Google Sign In
When using Google Sign In on mobile with ID tokens, nonce verification may fail because mobile SDKs do not always support the nonce flow expected by the Auth service. GOTRUE_EXTERNAL_SKIP_NONCE_CHECK can disable nonce validation, but this weakens replay-attack protection. Use only as a short-lived troubleshooting workaround, not a permanent fix. Enable only in the environment where debugging, then revert immediately. Prefer fixing client-side nonce handling or switching to an OAuth flow (authorization code with PKCE) that avoids ID-token nonce issues.
OAuth environment variable reference for self-hosted Supabase
All OAuth-related environment variables for the auth service in docker-compose.yml:
Variable | Description | Required
GOTRUE_EXTERNAL_*_ENABLED | Enable the provider (true/false) | Yes
GOTRUE_EXTERNAL_*_CLIENT_ID | OAuth client ID from the provider | Yes
GOTRUE_EXTERNAL_*_SECRET | OAuth client secret from the provider | Yes
GOTRUE_EXTERNAL_*_REDIRECT_URI | Callback URL: ${API_EXTERNAL_URL}/callback | Yes
GOTRUE_SITE_URL | Default redirect URL after authentication (set via SITE_URL in .env) | Yes
Check auth service logs for startup failures
If the Auth service fails to start in self-hosted Supabase, check the auth container logs with: docker compose logs auth. Common causes include: Missing required environment variable (CLIENT_ID or SECRET is empty), or invalid API_EXTERNAL_URL (must be a valid URL including protocol and ending with /auth/v1).
Install Laravel Breeze authentication template
Install Laravel Breeze as a basic implementation of Laravel's authentication features using the commands: composer require laravel/breeze --dev and php artisan breeze:install.
Laravel uses its own authentication instead of Supabase Auth
Laravel Breeze provides a basic implementation of Laravel's built-in authentication features. Laravel does not use Supabase Auth by default but implements its own authentication system. You can optionally replace Laravel's authentication with Supabase Auth if desired.
OAuth integration authorization URL and query parameters
To start the OAuth flow, redirect users to https://api.supabase.com/v1/oauth/authorize with these query parameters: client_id (required, your app's client ID), redirect_uri (required, where Supabase redirects after consent), response_type (required, set to 'code'), state (required, information about your app state; redirect_uri and state together cannot exceed 4kB), organization_slug (optional, pre-selects organization for user). PKCE is strongly recommended: generate a code verifier, hash it with SHA256, include as code_challenge parameter, and set code_challenge_method to S256.
OAuth token exchange endpoint and parameters
Exchange authorization code for tokens by POSTing to https://api.supabase.com/v1/oauth/token with content-type application/x-www-form-urlencoded. Required parameters: grant_type (set to 'authorization_code'), code (authorization code from callback), redirect_uri (must exactly match the authorize redirect_uri), code_verifier (recommended if using PKCE, the original code verifier). Authenticate using HTTP Basic Auth with client_id and client_secret as base64-encoded credentials.
OAuth callback parameters from Supabase
After user consent, Supabase redirects to your redirect_uri with query parameters: code (authorization code to exchange for tokens), state (the value you provided earlier, must be validated to match).
Refreshing OAuth access tokens
Use the POST /v1/oauth/token endpoint with a refresh token to get a new access token. If the user revokes access, token refresh will fail and access tokens will stop working. Always handle HTTP Unauthorized errors when calling Supabase APIs.
TypeScript example: OAuth authorization redirect
Example showing how to redirect user to authorization endpoint:
```ts
router.get('/connect-supabase/login', async (ctx) => {
const { uri, codeVerifier } = await oauth2Client.code.getAuthorizationUri()
console.log(uri.toString())
ctx.state.session.flash('codeVerifier', codeVerifier)
ctx.response.redirect(uri)
})
```
This generates the authorization URI with PKCE parameters, stores the code verifier in session for later use, and redirects the user.
TypeScript example: OAuth callback and token exchange
Example showing how to handle callback and exchange authorization code for tokens:
```ts
router.get('/connect-supabase/oauth2/callback', async (ctx) => {
const codeVerifier = ctx.state.session.get('codeVerifier') as string
if (!codeVerifier) throw new Error('No codeVerifier!')
const tokens = await fetch(config.tokenUri, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
Authorization: `Basic ${btoa(`${config.clientId}:${config.clientSecret}`)}`,
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: ctx.request.url.searchParams.get('code') || '',
redirect_uri: config.redirectUri,
code_verifier: codeVerifier,
}),
}).then((res) => res.json())
ctx.response.body = 'Success'
})
```
This retrieves the code verifier from session, exchanges the authorization code with proper PKCE parameters for tokens, and stores them.
Creating OAuth app in Supabase dashboard
To create a Supabase OAuth app: navigate to your organization's settings and the OAuth Apps tab, click Add application in the upper-right section, fill in required details, and click Confirm.
Configure custom SMTP for Auth via Management API
Use the /config/auth endpoint in the Management API to configure custom SMTP settings for the user's authentication.
Handle dynamic redirect URLs in OAuth with state parameter
To support multiple dynamically generated redirect URLs within the same OAuth app, encode the desired redirect URL in the state parameter when starting OAuth. After authorization, extract and decode the state value to determine the correct redirect URL. Verify state integrity before using it.
OAuth integration current limitations
Fine-grained access control is not yet fully available. If an integration needs full database access, it must prompt the user for their database password.
Auth0 to Supabase migration overview
Migrating users from Auth0 to Supabase Auth requires 2 main steps: exporting user data from Auth0 and importing it into Supabase Auth. Before beginning, consider cost scaling, feature availability, acceptable downtime, and migration timeline.
Migration strategies: Rolling vs One-off
Rolling migration offers 0 downtime but requires maintaining 2 auth services and separate codepaths. One-off migration has no need for dual services but requires some downtime and users must log in again. Rolling is better for active users; one-off is simpler for smaller-scale backfill of inactive users.
Export user data from Auth0
Auth0 provides two export methods: the Auth0 data export feature and the Auth0 management API (which has rate limits requiring batch exports). To export password hashes and MFA factors, contact Auth0 support.
Migrate password-based users to Supabase
For password-based users: first filter Auth0 exports for users with 'auth0' as the provider in the identities field. Match users by Auth0 user_id to password hash export oid field. Use Supabase Auth admin createUser method with password_hash (supports bcrypt and Argon2) or plaintext password. Set email_confirm or phone_confirm to true if the user has a confirmed email or phone.
Supabase admin createUser with password hash
Example code for creating a user with a password hash in Supabase Auth:
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('your_project_url', 'your_supabase_api_key')
const { data, error } = await supabase.auth.admin.createUser({
email: 'valid.email@supabase.io',
password_hash: '$2y$10$a9pghn27d7m0ltXvlX8LiOowy7XfFw0hW0G80OjKYQ1jaoejaA7NC',
email_confirm: true,
})
```
Supabase admin createUser with plaintext password
Example code for creating a user with a plaintext password in Supabase Auth:
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('your_project_url', 'your_supabase_api_key')
const { data, error } = await supabase.auth.admin.createUser({
email: 'valid.email@supabase.io',
password: 'sup••••••23!',
})
```
Fallback strategy for password migration
To handle users not successfully migrated, use a fallback strategy: try to sign in with Supabase Auth first. If signin fails, try Auth0 signin. If Auth0 signin succeeds, call admin createUser again to create the user in Supabase Auth.
Migrate passwordless users to Supabase
For passwordless signin via email or phone, check for users with verified email addresses or phone numbers. Create these users in Supabase Auth using admin createUser with email_confirm or phone_confirm set to true. Configure email templates for magic links and use signInWithOtp method for signin.
Migrate passwordless users example
Example code for creating a passwordless user in Supabase Auth:
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('your_project_url', 'your_supabase_api_key')
const { data, error } = await supabase.auth.admin.createUser({
email: 'valid.email@supabase.io',
email_confirm: true,
})
```
OAuth migration strategy
For OAuth providers, configure them in Supabase using Social login guides. Use signInWithOAuth method for both new and existing users. Pre-migration is not needed since users must sign in through the OAuth provider first. Map existing Auth0 users by social provider ID (format: provider_name|provider_id, e.g. github|123456).
Supabase Auth user storage schema
In Supabase Auth, users are stored in the auth schema. Each user has an identity representing the signin method, represented by auth.users and auth.identities tables.
Supabase user metadata fields
Supabase Auth provides two metadata fields: raw_user_meta_data (for non-sensitive user metadata that the user can update, e.g. full name, age) and raw_app_meta_data (for non-sensitive metadata that the user should not update, e.g. pricing plan, access control roles). Both are accessible from admin user methods and stored as jsonb type in auth.users table.
Create Supabase user with metadata
Example code for creating a user with custom metadata in Supabase Auth:
```ts
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('your_project_url', 'your_supabase_api_key')
const { data, error } = await supabase.auth.admin.createUser({
email: 'valid.email@supabase.io',
user_metadata: {
full_name: 'Foo Bar',
},
app_metadata: {
role: 'admin',
},
})
```