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:
// 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). Usesupabase.auth.mfa.enroll({ factorType: 'totp' }), thenchallengeandverify. The session reachesaal2. - Security key as a second step (
mfa_webauthn_enabled): usesupabase.auth.mfa.webauthn.register(...)andsupabase.auth.mfa.webauthn.authenticate(...).
SAML single sign-on
On the Pro and Studio plans. Open Authentication > SSO:
- Turn on SAML. The signing key is generated for you and never shown.
- Give your identity provider the two URLs the page shows: the metadata URL (also the entity ID) and the reply URL (ACS).
- Connect it with its metadata URL or metadata file, and the email domains it signs in.
In the app:
const { data, error } = await supabase.auth.signInWithSSO({ domain: 'example.com' })
// data.url is the identity provider's sign-in pageOne 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:
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).