docs: Update documentation from dart SDK changes (#47006)

## Summary

Updates docs based on stable releases in `supabase/supabase-flutter`.

## Changes analyzed

- **SDK**: dart
- **Repo**: https://github.com/supabase/supabase-flutter
- **Stable tag range**:
`supabase_flutter-v2.14.1...supabase_flutter-v2.15.0`
- **Commits**:
`81c1590728a5e08bebdc152bd59a7c1e7644c8b2...9030650b74e253020f8c614b3bfb2c993b6061af`

## Documentation updates

`apps/docs/spec/supabase_dart_v2.yml` — adds entries for the new passkey
APIs landed in `supabase_flutter-v2.15.0`
([gotrue#1392](https://github.com/supabase/supabase-flutter/pull/1392),
[supabase_flutter#1408](https://github.com/supabase/supabase-flutter/pull/1408)):

- `signInWithPasskey()` / `registerPasskey()` — high-level helpers on
`supabase_flutter` that drive the full WebAuthn ceremony.
- `auth.passkey.*` — server side of the WebAuthn ceremony: `list`,
`update`, `delete`, `startRegistration`, `verifyRegistration`,
`startAuthentication`, `verifyAuthentication`.
- `auth.admin.passkey.*` — admin endpoints: `listPasskeys`,
`deletePasskey`.

`apps/docs/content/guides/auth/passkeys.mdx` — adds Dart code examples
to every passkey section (Enable in the client, Register, Sign in,
Two-step API, Manage, Admin API) and points the reference links at both
the JavaScript and Dart specs. Bumps the "Requires" admonition to
include `supabase_flutter v2.15.0`.

Other v2.14.2 / v2.15.0 changes that did not require doc updates:

- `feat(realtime): protocol format 2.0.0` — protocol versions are
already documented in `realtime/protocol.mdx`; the SDK now defaults to
v2.0.0 but exposes a `version: RealtimeProtocolVersion.v1` opt-out,
which is an SDK detail rather than a docs change.
- `fix(gotrue): support asymmetric JWTs in getClaims` — bug fix to the
existing `auth.getClaims` (no new API).
- The rest are bug fixes and internal refactors (storage
`createSignedUrls` null handling, postgrest stack traces, gotrue
refresh-token races, PKCE email-change, realtime deaf-socket guards,
lint/test/CI hygiene).

`common-client-libs-sections.json` already contains entries for every
new spec `id`, so the sidebar nav picks them up automatically.

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added Dart language examples to passkey authentication guide covering
client initialization, user registration, sign-in workflows, two-step
ceremony flows, and passkey management operations
* Updated Dart client specification to document new passkey
authentication functions and admin-level passkey management capabilities

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Guilherme Souza authored and GitHub committed 2026-06-17 06:12:54 -03:00
1 parent 96d43099bb
commit f4c3e26fd7
2 files changed
+439 -10

No files matched your search

+192 -10
View File
@@ -14,7 +14,7 @@ Passkey support is experimental. The API may change without notice. You must exp
<Admonition type="note">
**Requires `@supabase/supabase-js` v2.105.0 and later.** Upgrade your client library to use passkey authentication.
**Requires `@supabase/supabase-js` v2.105.0 and later, or `supabase_flutter` v2.15.0 and later.** Upgrade your client library to use passkey authentication.
</Admonition>
@@ -23,7 +23,7 @@ Passkey support is experimental. The API may change without notice. You must exp
Each sign-in or registration is a WebAuthn ceremony with three steps:
1. **Options**: the client requests a challenge from Supabase Auth.
2. **Ceremony**: the browser invokes `navigator.credentials.create()` (registration) or `navigator.credentials.get()` (authentication), prompting the user for biometrics or a security key.
2. **Ceremony**: the platform's passkey API (`navigator.credentials.create()` / `get()` on web, or a passkey plugin on iOS, Android, and macOS) prompts the user for biometrics or a security key.
3. **Verify**: the signed response is sent back to Supabase Auth, which validates the challenge and either stores the new credential or issues a session.
Supabase Auth uses [discoverable credentials](https://www.w3.org/TR/webauthn-3/#discoverable-credential) for sign-in. The user does not need to provide an email, phone, or username — the authenticator resolves the account from the credential it stores.
@@ -99,6 +99,15 @@ Passkey support is currently experimental and requires explicit opt-in as the AP
</Admonition>
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```ts
import { createClient } from '@supabase/supabase-js'
@@ -109,11 +118,40 @@ const supabase = createClient(supabaseUrl, supabaseKey, {
})
```
</TabPanel>
<TabPanel id="dart" label="Dart">
The Dart SDK does not require an opt-in flag — the methods are annotated `@experimental` so the analyzer surfaces them as preview API. The server independently rejects calls with `passkey_disabled` when the dashboard toggle is off.
```dart
import 'package:supabase_flutter/supabase_flutter.dart';
await Supabase.initialize(
url: supabaseUrl,
anonKey: supabaseAnonKey,
);
final supabase = Supabase.instance.client;
```
Platform setup that the library cannot do for you (Associated Domains on iOS/macOS, Digital Asset Links on Android, and including the [`passkeys`](https://pub.dev/packages/passkeys) web SDK in `index.html` on web) is documented in the `supabase_flutter` package README.
</TabPanel>
</Tabs>
## Register a passkey
A user must be signed in before they can register a passkey. Typically, you call this from a security settings page, or directly after sign-up.
`auth.registerPasskey()` runs the full WebAuthn ceremony. It fetches a challenge, invokes the browser API, and verifies the response with Supabase Auth.
`auth.registerPasskey()` runs the full WebAuthn ceremony. It fetches a challenge, invokes the platform passkey API, and verifies the response with Supabase Auth.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```ts
const { data, error } = await supabase.auth.registerPasskey()
@@ -126,11 +164,30 @@ if (error) {
}
```
The returned `data` contains the new passkey's metadata:
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
try {
final Passkey passkey = await supabase.auth.registerPasskey();
print('Registered passkey ${passkey.id}');
} on AuthException catch (e) {
// The Supabase server rejected the credential.
print(e);
} catch (e) {
// User cancelled or the platform ceremony failed.
print(e);
}
```
</TabPanel>
</Tabs>
The returned passkey contains the new credential's metadata:
```ts
{
id: string // UUID — use this to update or delete the passkey
id: string // UUID — use this to update or delete the passkey
friendly_name?: string // Derived from the authenticator's AAGUID
created_at: string
}
@@ -138,12 +195,21 @@ The returned `data` contains the new passkey's metadata:
A friendly name is automatically derived from the authenticator's Authenticator Attestation GUID (AAGUID). For example, `iCloud Keychain`, `Google Password Manager`, `1Password`. Users can rename their passkey afterwards — see [Manage passkeys](#manage-passkeys).
See the [`registerPasskey` reference](/docs/reference/javascript/auth-registerpasskey) for the full API.
See the `registerPasskey` reference ([JavaScript](/docs/reference/javascript/auth-registerpasskey) · [Dart](/docs/reference/dart/auth-registerpasskey)) for the full API.
## Sign in with a passkey
`auth.signInWithPasskey()` runs the full discoverable-credential authentication ceremony. The user picks an account from the authenticator's UI — your app does not need to ask for an email or phone number upfront.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```ts
const { data, error } = await supabase.auth.signInWithPasskey()
@@ -155,12 +221,37 @@ if (error) {
}
```
See the [`signInWithPasskey` reference](/docs/reference/javascript/auth-signinwithpasskey) for the full API.
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
try {
final AuthResponse res = await supabase.auth.signInWithPasskey();
// res.session and res.user are set; the client also fires AuthChangeEvent.signedIn
print('Signed in as ${res.user?.email}');
} on AuthException catch (e) {
print(e);
}
```
</TabPanel>
</Tabs>
See the `signInWithPasskey` reference ([JavaScript](/docs/reference/javascript/auth-signinwithpasskey) · [Dart](/docs/reference/dart/auth-signinwithpasskey)) for the full API.
## Two-step API
For native flows, custom UI, or full control over the WebAuthn ceremony, use the lower-level `auth.passkey` namespace. Each operation is split into "start" and "verify".
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
Registration:
```ts
@@ -185,14 +276,57 @@ const { data } = await supabase.auth.passkey.verifyAuthentication({
})
```
</TabPanel>
<TabPanel id="dart" label="Dart">
Registration:
```dart
final registration = await supabase.auth.passkey.startRegistration();
// Run the platform ceremony yourself (e.g. using a passkey plugin).
final Map<String, dynamic> credential = await runRegistrationCeremony(
registration.options,
);
final passkey = await supabase.auth.passkey.verifyRegistration(
challengeId: registration.challengeId,
credential: credential,
);
```
Authentication:
```dart
final authentication = await supabase.auth.passkey.startAuthentication();
// Run the platform ceremony yourself (e.g. using a passkey plugin).
final Map<String, dynamic> credential = await runAuthenticationCeremony(
authentication.options,
);
final AuthResponse res = await supabase.auth.passkey.verifyAuthentication(
challengeId: authentication.challengeId,
credential: credential,
);
```
</TabPanel>
</Tabs>
The `options` field returned from `startRegistration` and `startAuthentication` matches the [WebAuthn `PublicKeyCredentialCreationOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialcreationoptions) and [`PublicKeyCredentialRequestOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialrequestoptions) shapes (with `ArrayBuffer` fields encoded as base64url).
See the [`auth.passkey` reference](/docs/reference/javascript/auth-passkey-api) for the full API.
See the `auth.passkey` reference ([JavaScript](/docs/reference/javascript/auth-passkey-api) · [Dart](/docs/reference/dart/auth-passkey-api)) for the full API.
## Manage passkeys
List, rename, and delete the current user's passkeys:
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```ts
// List
const { data: passkeys } = await supabase.auth.passkey.list()
@@ -208,14 +342,43 @@ await supabase.auth.passkey.update({
await supabase.auth.passkey.delete({ passkeyId: passkeys[0].id })
```
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
// List
final List<Passkey> passkeys = await supabase.auth.passkey.list();
// Rename
await supabase.auth.passkey.update(
passkeyId: passkeys.first.id,
friendlyName: 'Work laptop',
);
// Delete
await supabase.auth.passkey.delete(passkeyId: passkeys.first.id);
```
</TabPanel>
</Tabs>
`friendlyName` is limited to 120 characters. `last_used_at` is updated each time the passkey is used to sign in.
See the [`auth.passkey` reference](/docs/reference/javascript/auth-passkey-api) for the full API.
See the `auth.passkey` reference ([JavaScript](/docs/reference/javascript/auth-passkey-api) · [Dart](/docs/reference/dart/auth-passkey-api)) for the full API.
## Admin API
Server-side admin endpoints let you inspect and revoke a user's passkeys. These require the project's secret key and must only be called from a trusted server.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="js"
queryGroup="language"
>
<TabPanel id="js" label="JavaScript">
```ts
import { createClient } from '@supabase/supabase-js'
@@ -228,7 +391,26 @@ const { data } = await supabase.auth.admin.passkey.listPasskeys({ userId })
await supabase.auth.admin.passkey.deletePasskey({ userId, passkeyId })
```
See the [`auth.admin.passkey` reference](/docs/reference/javascript/auth-admin-passkey-api) for the full API.
</TabPanel>
<TabPanel id="dart" label="Dart">
```dart
final supabase = SupabaseClient(supabaseUrl, secretKey);
final List<Passkey> passkeys = await supabase.auth.admin.passkey.listPasskeys(
userId: userId,
);
await supabase.auth.admin.passkey.deletePasskey(
userId: userId,
passkeyId: passkeyId,
);
```
</TabPanel>
</Tabs>
See the `auth.admin.passkey` reference ([JavaScript](/docs/reference/javascript/auth-admin-passkey-api) · [Dart](/docs/reference/dart/auth-admin-passkey-api)) for the full API.
## Error codes
+247
View File
@@ -883,6 +883,48 @@ functions:
providerId: '21648a9d-8d5a-4555-a9d1-d6375dc14e92',
);
```
- id: sign-in-with-passkey
title: 'signInWithPasskey()'
notes: |
Signs the user in with a passkey (WebAuthn).
- Available on `supabase_flutter` 2.15.0 and later as an extension on `GoTrueClient`.
- Drives the full WebAuthn ceremony end to end: starts the challenge with the Supabase server, prompts the user for biometrics or a security key via the platform passkey API, and verifies the credential with the server.
- Does not require an existing session. On success the session is persisted and an `AuthChangeEvent.signedIn` event is fired.
- For native flows or custom UI, use the lower-level [`auth.passkey`](/docs/reference/dart/auth-passkey-api) namespace instead.
- Passkeys are a BETA feature and must be enabled for your project in the Supabase Dashboard under Authentication > Configuration > Passkeys.
- Platform setup the library cannot perform (Associated Domains on iOS/macOS, Digital Asset Links on Android, the `passkeys` web SDK on web) is documented in the `supabase_flutter` package README.
params:
- name: captchaToken
isOptional: true
type: String
description: Captcha token to be used for captcha verification.
examples:
- id: sign-in-with-passkey
name: Sign in with a passkey
isSpotlight: true
code: |
```dart
final AuthResponse res = await supabase.auth.signInWithPasskey();
final Session? session = res.session;
final User? user = res.user;
```
- id: register-passkey
title: 'registerPasskey()'
notes: |
Registers a new passkey (WebAuthn credential) for the signed in user.
- Available on `supabase_flutter` 2.15.0 and later as an extension on `GoTrueClient`.
- Drives the full WebAuthn ceremony end to end: starts the registration with the Supabase server, prompts the user to create a credential on the device, and verifies it with the server.
- Requires a signed in (non-anonymous) user. If the user has verified MFA factors, the session has to be at `aal2` to manage passkeys.
- For native flows or custom UI, use the lower-level [`auth.passkey`](/docs/reference/dart/auth-passkey-api) namespace instead.
- Passkeys are a BETA feature and must be enabled for your project in the Supabase Dashboard under Authentication > Configuration > Passkeys.
examples:
- id: register-passkey
name: Register a passkey for the current user
isSpotlight: true
code: |
```dart
final Passkey passkey = await supabase.auth.registerPasskey();
```
- id: sign-out
title: 'signOut()'
description: |
@@ -2111,6 +2153,162 @@ functions:
]
}
```
- id: passkey-api
title: 'Auth Passkey'
notes: |
This section contains methods for WebAuthn passkey registration, authentication, and management. Methods are invoked behind the `supabase.auth.passkey` namespace.
These methods expose the server side of the WebAuthn ceremony. The client side (the FaceID/TouchID/security key prompt) has to be performed with a platform passkey API: `navigator.credentials.create()`/`get()` on web, or a passkey plugin on iOS/Android/macOS. Options and credentials are exchanged as `Map<String, dynamic>` in the W3C WebAuthn Level 3 JSON format.
For a one-call alternative that runs the full ceremony, see [`signInWithPasskey()`](/docs/reference/dart/auth-signinwithpasskey) and [`registerPasskey()`](/docs/reference/dart/auth-registerpasskey) on `supabase_flutter`.
Passkey support is a BETA feature and must be enabled for your project in the Supabase Dashboard under Authentication > Configuration > Passkeys.
- id: passkey-list
title: 'passkey.list()'
notes: |
Returns the list of passkeys registered to the signed in user.
examples:
- id: list-passkeys
name: List the current user's passkeys
isSpotlight: true
code: |
```dart
final List<Passkey> passkeys = await supabase.auth.passkey.list();
```
- id: passkey-update
title: 'passkey.update()'
notes: |
Updates the friendly name of a passkey.
params:
- name: passkeyId
isOptional: false
type: String
description: ID of the passkey to rename.
- name: friendlyName
isOptional: false
type: String
description: New human readable name for the passkey. Limited to 120 characters.
examples:
- id: rename-passkey
name: Rename a passkey
isSpotlight: true
code: |
```dart
final Passkey passkey = await supabase.auth.passkey.update(
passkeyId: '34e770dd-9ff9-416c-87fa-43b31d7ef225',
friendlyName: 'Work laptop',
);
```
- id: passkey-delete
title: 'passkey.delete()'
notes: |
Deletes a passkey from the signed in user.
- If the user has verified MFA factors, the session has to be at `aal2` to manage passkeys.
params:
- name: passkeyId
isOptional: false
type: String
description: ID of the passkey to delete.
examples:
- id: delete-passkey
name: Delete a passkey
isSpotlight: true
code: |
```dart
await supabase.auth.passkey.delete(
passkeyId: '34e770dd-9ff9-416c-87fa-43b31d7ef225',
);
```
- id: passkey-start-registration
title: 'passkey.startRegistration()'
notes: |
Starts the registration of a new passkey for the signed in user.
- Requires a signed in (non-anonymous) user.
- Pass the returned `options` to the platform's passkey API to create the credential, then call [`passkey.verifyRegistration()`](/docs/reference/dart/auth-passkey-verifyregistration) with the result.
examples:
- id: start-passkey-registration
name: Start a passkey registration
isSpotlight: true
code: |
```dart
final PasskeyRegistrationOptionsResponse registration =
await supabase.auth.passkey.startRegistration();
// Hand registration.options to the platform passkey API.
```
- id: passkey-verify-registration
title: 'passkey.verifyRegistration()'
notes: |
Completes the registration of a new passkey and returns the stored [`Passkey`](/docs/reference/dart/auth-passkey-api).
params:
- name: challengeId
isOptional: false
type: String
description: The challenge ID returned by `passkey.startRegistration()`.
- name: credential
isOptional: false
type: 'Map<String, dynamic>'
description: The credential created by the platform's passkey API, serialized in the W3C `RegistrationResponseJSON` format.
examples:
- id: verify-passkey-registration
name: Verify a passkey registration
isSpotlight: true
code: |
```dart
final Passkey passkey = await supabase.auth.passkey.verifyRegistration(
challengeId: registration.challengeId,
credential: credential,
);
```
- id: passkey-start-authentication
title: 'passkey.startAuthentication()'
notes: |
Starts a passkey sign in.
- Does not require an existing session.
- Pass the returned `options` to the platform's passkey API to obtain an assertion, then call [`passkey.verifyAuthentication()`](/docs/reference/dart/auth-passkey-verifyauthentication) with the result.
params:
- name: captchaToken
isOptional: true
type: String
description: Captcha token to be used for captcha verification.
examples:
- id: start-passkey-authentication
name: Start a passkey sign in
isSpotlight: true
code: |
```dart
final PasskeyAuthenticationOptionsResponse authentication =
await supabase.auth.passkey.startAuthentication();
// Hand authentication.options to the platform passkey API.
```
- id: passkey-verify-authentication
title: 'passkey.verifyAuthentication()'
notes: |
Completes a passkey sign in and returns the new session.
- On success the session is persisted and an `AuthChangeEvent.signedIn` event is fired.
params:
- name: challengeId
isOptional: false
type: String
description: The challenge ID returned by `passkey.startAuthentication()`.
- name: credential
isOptional: false
type: 'Map<String, dynamic>'
description: The assertion produced by the platform's passkey API, serialized in the W3C `AuthenticationResponseJSON` format.
examples:
- id: verify-passkey-authentication
name: Verify a passkey sign in
isSpotlight: true
code: |
```dart
final AuthResponse res = await supabase.auth.passkey.verifyAuthentication(
challengeId: authentication.challengeId,
credential: credential,
);
final Session? session = res.session;
final User? user = res.user;
```
- id: admin-api
title: 'Overview'
notes: |
@@ -2594,6 +2792,55 @@ functions:
),
);
```
- id: admin-passkey-api
title: 'Passkey Admin API'
notes: |
Contains passkey administration methods, accessed under the `supabase.auth.admin.passkey` namespace. Requires a `secret` key.
Passkey support is a BETA feature and must be enabled for your project in the Supabase Dashboard under Authentication > Configuration > Passkeys.
- id: admin-list-passkeys
title: 'admin.passkey.listPasskeys()'
notes: |
Returns the list of passkeys registered to the user with the given ID.
params:
- name: userId
isOptional: false
type: String
description: User ID whose passkeys should be returned.
examples:
- id: admin-list-passkeys
name: List a user's passkeys
isSpotlight: true
code: |
```dart
final List<Passkey> passkeys = await supabase.auth.admin.passkey.listPasskeys(
userId: '11111111-1111-1111-1111-111111111111',
);
```
- id: admin-delete-passkey
title: 'admin.passkey.deletePasskey()'
notes: |
Deletes a passkey from a user.
params:
- name: userId
isOptional: false
type: String
description: User ID that owns the passkey.
- name: passkeyId
isOptional: false
type: String
description: ID of the passkey to delete.
examples:
- id: admin-delete-passkey
name: Delete a user's passkey
isSpotlight: true
code: |
```dart
await supabase.auth.admin.passkey.deletePasskey(
userId: '11111111-1111-1111-1111-111111111111',
passkeyId: '34e770dd-9ff9-416c-87fa-43b31d7ef225',
);
```
- id: invoke
title: 'invoke()'
description: |