navigator.credentials behind an Apple-approved-browser entitlement — the webview cannot run WebAuthn on macOS at all.
Two ways passkeys become unavailable
They surface differently on purpose:Device capability
getPasskeyCapability() answers “can this device run a prompt?”. Free, offline, no network. Check it before rendering any passkey UI.Project configuration
Passkeys disabled on the server surfaces as a
configuration error at call time, with the offending setting named in the message.Ceremony providers
The OS prompt runs behind aCeremonyProvider trait. Precedence:
- An app-supplied provider via
PluginBuilder::ceremony_provider - The built-in provider for the compile target
- Neither — passkeys report unusable
Both built-ins are compiled behind
cfg(target_os = …), so a Linux build carries neither.
Supplying your own
options is passed through verbatim as the server’s WebAuthn options JSON, and CeremonyOutcome::Cancelled is a first-class non-error outcome. Providers are invoked on a blocking thread and no timeout of the plugin’s spans the prompt — the server’s challenge TTL is the effective ceiling.
The JavaScript route needs the four two-step permissions granted.
Project prerequisites
One-time work for the project owner:1
Enable passkeys
Dashboard under Authentication → Passkeys, or
[auth.passkey] enabled = true in supabase/config.toml for a local stack, or GOTRUE_PASSKEY_ENABLED=true self-hosted.2
Set the relying-party config
GOTRUE_WEBAUTHN_RP_ID (a bare domain you control), GOTRUE_WEBAUTHN_RP_DISPLAY_NAME, and GOTRUE_WEBAUTHN_RP_ORIGINS — which must include the origin your ceremony asserts.3
Optional limits
GOTRUE_PASSKEY_MAX_PASSKEYS_PER_USER (default 10) and GOTRUE_WEBAUTHN_CHALLENGE_EXPIRY_DURATION (default 5 minutes).4
macOS only: associated domains
A signed build, an App ID with the Associated Domains capability, and an
apple-app-site-association file with webcredentials served over HTTPS from https://<rp-id>/.well-known/apple-app-site-association.Using it
Traps worth knowing
- Registration always requires an authenticated user. A passkey binds to an existing account, so there is no passkey-first sign-up. Sign in another way, then register.
- Deleting the last passkey is not blocked server-side. Warn before it happens in your UI, and keep another sign-in method on every account.
- On macOS, an unentitled build reports passkeys as usable. Availability keys on the macOS version floor alone, so the entitlement failure only surfaces at prompt time. A build that looks fine can fail at the prompt.
rp_idcannot staylocalhostfor macOS native ceremonies. An associated domain must be a real domain you control, sorp_idandrp_originsboth have to move — and movingrp_idinvalidates enrolled passkeys.

