# Configure Passkey Authentication

Set up passkey authentication for self-hosted Supabase.

## Overview

[Passkeys](https://fidoalliance.org/passkeys/) are passwordless, phishing-resistant credentials built on the [WebAuthn](https://www.w3.org/TR/webauthn-3/) standard. This guide covers the server-side configuration to enable passkey authentication in a self-hosted Supabase instance. For how passkeys work and how to use them from a client, see the [Passkey authentication](https://supabase.com/docs/guides/auth/passkeys) guide.

## Enable passkey authentication

For self-hosted Supabase, passkey authentication is configured through environment variables passed to the auth service in `docker-compose.yml`. The variables below control passkey authentication and WebAuthn configuration.

| Variable                                    | Description                                                                                                                                                                                                                                                  | Default |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| `GOTRUE_PASSKEY_ENABLED`                    | Enables passkey authentication.                                                                                                                                                                                                                              | `false` |
| `GOTRUE_PASSKEY_MAX_PASSKEYS_PER_USER`      | Maximum number of passkeys a single user can register.                                                                                                                                                                                                       | `10`    |
| `GOTRUE_WEBAUTHN_RP_ID`                     | The bare domain name for your application (the WebAuthn [relying party](https://www.w3.org/TR/webauthn-3/#relying-party) ID). Do not include a scheme, port, or path. This determines which passkeys can be used. **Required when passkey auth is enabled.** | -       |
| `GOTRUE_WEBAUTHN_RP_DISPLAY_NAME`           | A human-readable name for your application, shown during the passkey prompt. **Required when passkey auth is enabled.**                                                                                                                                      | -       |
| `GOTRUE_WEBAUTHN_RP_ORIGINS`                | Comma-separated list of allowed origins (for example, `https://example.com,https://app.example.com`). **Required when passkey auth is enabled.**                                                                                                             | -       |
| `GOTRUE_WEBAUTHN_CHALLENGE_EXPIRY_DURATION` | How long a WebAuthn challenge remains valid. If the ceremony isn't completed within this window, the client must request a new challenge.                                                                                                                    | `5m`    |

### Configure the Auth service

Add the environment variables to the `auth` service in your `docker-compose.yml`:

```yml name=docker-compose.yml
services:
  auth:
    environment:
      # ... existing variables ...
      GOTRUE_PASSKEY_ENABLED: true
      GOTRUE_PASSKEY_MAX_PASSKEYS_PER_USER: 10 # optional - default is 10
      GOTRUE_WEBAUTHN_RP_ID: example.com
      GOTRUE_WEBAUTHN_RP_DISPLAY_NAME: my-app
      GOTRUE_WEBAUTHN_RP_ORIGINS: https://example.com,https://app.example.com
      GOTRUE_WEBAUTHN_CHALLENGE_EXPIRY_DURATION: 5m # optional - default is 5 minutes
```

WebAuthn requires a secure context, so when setting `GOTRUE_WEBAUTHN_RP_ORIGINS`, keep the following requirements in mind:

- Origins must use HTTPS, except for loopback addresses (`localhost`, `127.0.0.1`, `[::1]`).
- Each origin's hostname must match or be a subdomain of `GOTRUE_WEBAUTHN_RP_ID`.
- Android native apps can use an app origin of the form `android:apk-key-hash:<base64url SHA-256 of the signing certificate>`.

For local testing, set `GOTRUE_WEBAUTHN_RP_ID` to `localhost` and use `http://localhost:3000` as the origin.

Caution: Passkeys are cryptographically bound to the Relying Party (RP) ID they were registered against. Changing the RP ID makes every existing passkey unusable for sign-in, and users will need to register a new one. Pick the RP ID carefully before users start enrolling, and keep it stable once they do.

### Relaunch the Auth service

After updating the environment variables, relaunch the auth service for the changes to take effect:

```bash
sh run.sh recreate auth
```

### Verify passkeys are enabled

Request an authentication challenge to confirm the auth service picked up the configuration:

```sh
curl -X POST 'http://<your-domain>/auth/v1/passkeys/authentication/options' \
  -H 'apikey: your-supabase-publishable-key'
```

A `200` response containing a `challenge_id` confirms that passkey authentication is enabled. A `passkey_disabled` error means the auth service did not pick up the configuration.

## Manage a user's passkeys

Use the Auth admin API to inspect or revoke a user's passkeys from a trusted server, for example to remove a lost device. These calls require your project's secret key, `SUPABASE_SECRET_KEY`, from your `.env` file and must never run in client code.

The [Management API](https://supabase.com/docs/guides/auth/passkeys#management-api) covered in the client guide targets `api.supabase.com` and isn't available for self-hosted deployments. Configure passkeys with the environment variables above, and manage individual passkeys with the admin endpoints below.

### List a user's passkeys

```sh
curl 'http://<your-domain>/auth/v1/admin/users/{user_id}/passkeys' \
  -H 'apikey: your-supabase-secret-key'
```

### Delete a user's passkey

```sh
curl -X DELETE 'http://<your-domain>/auth/v1/admin/users/{user_id}/passkeys/{passkey_id}' \
  -H 'apikey: your-supabase-secret-key'
```

Deleting a user's last passkey removes their ability to sign in with a passkey until they register a new one.

## Next steps

After you enable passkeys in your self-hosted Auth service, configure the client exactly as you would for a hosted project: opt in when you create the Supabase client, register a passkey, and sign in. See [Enable in the client](https://supabase.com/docs/guides/auth/passkeys#enable-in-the-client).
