From f4c3e26fd738f1a3d97733aa817c8da4bfa38415 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 17 Jun 2026 06:12:54 -0300 Subject: [PATCH] docs: Update documentation from dart SDK changes (#47006) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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) ## 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 --- apps/docs/content/guides/auth/passkeys.mdx | 202 ++++++++++++++++- apps/docs/spec/supabase_dart_v2.yml | 247 +++++++++++++++++++++ 2 files changed, 439 insertions(+), 10 deletions(-) diff --git a/apps/docs/content/guides/auth/passkeys.mdx b/apps/docs/content/guides/auth/passkeys.mdx index d97e1ed3f31..0b7c12ae2d5 100644 --- a/apps/docs/content/guides/auth/passkeys.mdx +++ b/apps/docs/content/guides/auth/passkeys.mdx @@ -14,7 +14,7 @@ Passkey support is experimental. The API may change without notice. You must exp -**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. @@ -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 + + + ```ts import { createClient } from '@supabase/supabase-js' @@ -109,11 +118,40 @@ const supabase = createClient(supabaseUrl, supabaseKey, { }) ``` + + + +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. + + + + ## 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. + + + ```ts const { data, error } = await supabase.auth.registerPasskey() @@ -126,11 +164,30 @@ if (error) { } ``` -The returned `data` contains the new passkey's metadata: + + + +```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); +} +``` + + + + +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. + + + ```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. + + + +```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); +} +``` + + + + +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". + + + Registration: ```ts @@ -185,14 +276,57 @@ const { data } = await supabase.auth.passkey.verifyAuthentication({ }) ``` + + + +Registration: + +```dart +final registration = await supabase.auth.passkey.startRegistration(); +// Run the platform ceremony yourself (e.g. using a passkey plugin). +final Map 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 credential = await runAuthenticationCeremony( + authentication.options, +); +final AuthResponse res = await supabase.auth.passkey.verifyAuthentication( + challengeId: authentication.challengeId, + credential: credential, +); +``` + + + + 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: + + + ```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 }) ``` + + + +```dart +// List +final List 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); +``` + + + + `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. + + + ```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. + + + +```dart +final supabase = SupabaseClient(supabaseUrl, secretKey); + +final List passkeys = await supabase.auth.admin.passkey.listPasskeys( + userId: userId, +); + +await supabase.auth.admin.passkey.deletePasskey( + userId: userId, + passkeyId: passkeyId, +); +``` + + + + +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 diff --git a/apps/docs/spec/supabase_dart_v2.yml b/apps/docs/spec/supabase_dart_v2.yml index 2f17b096cad..4371c692617 100644 --- a/apps/docs/spec/supabase_dart_v2.yml +++ b/apps/docs/spec/supabase_dart_v2.yml @@ -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` 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 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' + 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' + 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 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: |