scribasedocs

Concepts

Passkeys, MFA and SAML

Each environment's auth service can sign your app's users in with passkeys, ask for a second step, and let a company's identity provider sign its people in. Turn them on in the console under Authentication > Sign-in methods, or with PATCH .../auth/config. Your app keeps using @supabase/supabase-js unchanged.

An environment that turns none of this on runs exactly as before.

Passkey sign-in

Turn on Passkey sign-in (passkey_enabled: true). In the app:

JavaScript
// Once, while signed in:
await supabase.auth.registerPasskey()

// Later, from the sign-in screen:
const { data, error } = await supabase.auth.signInWithPasskey()

The passkey domain (the WebAuthn relying party) is derived for you:

  • the domain is your site URL's host, else your first verified custom domain, else the project host;
  • the accepted origins are your site URL, the exact https:// entries of your redirect allow list and your verified custom domains, when they are on that domain or below it.

The console shows the derived domain under the switches. To set it yourself (a parent domain, or a native Android app's android:apk-key-hash: origin), use Advanced: webauthn_rp_id, webauthn_rp_display_name and webauthn_rp_origins (at most 20).

Two-step sign-in (MFA)

  • Authenticator app (TOTP) is on by default (mfa_totp_enabled). Use supabase.auth.mfa.enroll({ factorType: 'totp' }), then challenge and verify. The session reaches aal2.
  • Security key as a second step (mfa_webauthn_enabled): use supabase.auth.mfa.webauthn.register(...) and supabase.auth.mfa.webauthn.authenticate(...).

SAML single sign-on

On the Pro and Studio plans. Open Authentication > SSO:

  1. Turn on SAML. The signing key is generated for you and never shown.
  2. Give your identity provider the two URLs the page shows: the metadata URL (also the entity ID) and the reply URL (ACS).
  3. Connect it with its metadata URL or metadata file, and the email domains it signs in.

In the app:

JavaScript
const { data, error } = await supabase.auth.signInWithSSO({ domain: 'example.com' })
// data.url is the identity provider's sign-in page

One connection per environment to start. The routes are GET .../auth/sso, POST .../auth/sso/providers and DELETE .../auth/sso/providers/{id}.

Access token hook

Adds claims (a role, a plan) to every session token. Under Advanced, choose a SQL function or an edge function:

SQL
create or replace function public.custom_access_token_hook(event jsonb)
returns jsonb language plpgsql stable as $$
begin
  return jsonb_set(event, '{claims,plan}', to_jsonb('pro'::text));
end $$;
grant execute on function public.custom_access_token_hook(jsonb) to supabase_auth_admin;
revoke execute on function public.custom_access_token_hook(jsonb) from authenticated, anon, public;

An edge function hook is called over HTTPS and signed. Its secret is created for you as the environment secret AUTH_HOOK_CUSTOM_ACCESS_TOKEN_SECRET, so the function reads it from its environment. Redeploy the function after you turn the hook on.

Off unless you turn them on

Under Advanced: Sign in with Solana (web3_solana_enabled), Sign in with Ethereum (web3_ethereum_enabled) and the OAuth 2.1 server (oauth_server_enabled, with oauth_server_authorization_path, the consent page on your site URL).