Changelog

New updates and product improvements

undefined RSS

We're excited to announce the beta release of Passkeys for Supabase Auth — a passwordless, phishing-resistant credential built on the WebAuthn standard.

With passkeys, users sign in with biometrics (Face ID, Touch ID, Windows Hello), a device PIN, or a hardware security key. Supabase Auth stores the public key needed for verification; private key material remains managed by the user’s authenticator or credential provider.

How does it work?#

Each passkey enrollment or sign-in 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() (register) or navigator.credentials.get() (sign in), prompting the user to approve with 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, so users don't need to type an email or username — the authenticator resolves the account from the credential it already stores.

Enable passkeys in the Dashboard#

Open Authentication → Passkeys in the Dashboard, toggle on Enable Passkey authentication, and fill in your WebAuthn relying party details:

  • Relying Party Display Name: human-readable name shown during the passkey prompt (e.g. "My App").
  • Relying Party ID: your bare domain (e.g. example.com). No scheme, port, or path.
  • Relying Party Origins: up to 5 allowed origins (e.g. https://example.com,https://app.example.com).

The Dashboard pre-fills these from your project's Site URL and project name.

Passkeys can also be configured via the CLI and the Management API.

Use it from your app#

[!NOTE] The Passkeys API is currently experimental and requires an explicit opt-in as the API may change without notice during the beta phase.

Opt in to the experimental API when creating the client:


_10
import { createClient } from '@supabase/supabase-js'
_10
_10
const supabase = createClient(supabaseUrl, supabasePublishableKey, {
_10
auth: {
_10
experimental: { passkey: true },
_10
},
_10
})

Register a passkey for an authenticated user — typically from a security settings page or right after sign-up:


_10
const { data, error } = await supabase.auth.registerPasskey()
_10
// data: { id, friendly_name, created_at }

Sign in with a passkey — no email or phone needed upfront; the authenticator picks the account:


_10
const { data, error } = await supabase.auth.signInWithPasskey()
_10
// data.session and data.user are set; a SIGNED_IN event is dispatched

Manage passkeys — list, rename, and delete from the current user's account:


_10
const { data: passkeys } = await supabase.auth.passkey.list()
_10
_10
await supabase.auth.passkey.update({
_10
passkeyId: passkeys[0].id,
_10
friendlyName: 'Work laptop',
_10
})
_10
_10
await supabase.auth.passkey.delete({ passkeyId: passkeys[0].id })

What we'd like to know from you#

  • Any bugs or rough edges you hit during passkey registration or sign-in flows.
  • Friction when configuring the relying-party settings in the Dashboard, CLI, or Management API.
  • Feedback on integrating passkeys in native or mobile flows.
  • Suggestions for improving the API ergonomics or documentation.

Drop your feedback in this thread or open an issue.

Connect to your database using a temporary access token#

We are enabling an experimental feature that allows direct, temporary database access using user tokens, such as Personal Access Tokens (PATs).

This feature allows giving developers direct database access, as a specific role, without ever disclosing the database password.

Project administrators specify the database role a project user is allowed to access the database as, and the time period for which that access is valid. Because the credential (token) is tied directly to a specific user, it will be possible to see who accessed the database, and with which role. Revoking project access from a developer, immediately revokes their ability to log into the database.

This setting is only available to project owners and administrators.

Enabling the feature preview#

Database users must be enabled through the feature preview: https://supabase.com/dashboard/org/_/?featurePreviewModal=supabase-ui-jit-db-access

Configure access#

By default, Temporary token-based access is disabled and must be enabled on a per project basis. In your project’s database settings, enable Temporary token-based access:

https://supabase.com/dashboard/project/_/database/settings

Once enabled, you can grant other team members access. This is managed through the Add rule button. Access control is fine grained per database role. A user can be granted access to one or more database roles. Expiry is tied directly to the role and can be scoped down to minutes or a maximum of 90 days.

Branches#

Temporary access is fully supported in branch projects. When enabling temporary access on the main project, temporary access will also be enabled for all existing and future branches.

Users access can be scoped to branches only.

Temporary access is particularly helpful when dealing with branches, as you don’t need to know or modify any passwords, your Personal Access Token is sufficient for gaining access.

Disabling#

Temporary token-based access can be disabled for all users at once through the settings screen. Users will regain their previous access if you re-enable Temporary token-based access. Individual user’s access can be controlled by modifying the rule for that specific user.

Connecting to the database with an Temporary token#

Once granted access, users can access the database using their Personal Access Token (PAT). Access works through both the Shared Pooler and directly to the database. Users will only be able to access database roles for which they have been granted access.

Shared pooler:


_10
psql "postgres://{role}.{database_ref}@aws-1-{region}.pooler.supabase.com:6543/postgres?sslmode=require&options=-c%20jit%3dtrue"

Direct access:


_10
psql "postgres://{role}@db.{database_ref}.supabase.co:5432/postgres?sslmode=require"

Current limitations#

This feature is only available to projects on Postgres 17+. Older Postgres versions are not, and will not, be supported.

Temporary token-based access requires a user to be a valid member of the project. At present it is not possible to give access to users that are not part of your project. We are working on adding support for non-project members to be invited. This will allow granting database access to an external contractor, for example, while not making them part of your Supabase project or organization.

Temporary token-based access is not available through the dedicated pooler (port 6543 on the database host).

Starting with pg_graphql 1.6.0 (shipping in new Supabase projects from 2026-06-15), GraphQL introspection is disabled by default.

Who is affected#

  • New projects created on or after 2026-06-15 will run pg_graphql 1.6.0+ and have introspection disabled by default.
  • Existing projects are not affected unless and until you upgrade pg_graphql to 1.6.0+ (e.g. by upgrading your project's Postgres version). Older projects keep their current behaviour.

What's changing#

Previously, __schema and __type queries worked without any configuration. From 1.6.0, they return an error unless you explicitly opt in:


_10
{ "errors": [{ "message": "Unknown field \"__schema\" on type Query" }] }

If your project uses any of the following, you'll need to opt in before relying on introspection:

  • Supabase Studio GraphQL explorer (GraphiQL) — uses introspection to display your schema and provide autocomplete
  • External GraphiQL or GraphQL Playground
  • Apollo DevTools
  • Relay compiler
  • Code generators (e.g. graphql-codegen)
  • Any tool that calls __schema or __type directly

Regular data queries are not affected. accountCollection, insertIntoAccountCollection, etc. continue to work normally regardless of this setting.

How to opt in#

Run this SQL once per schema you want to expose introspection on:


_10
comment on schema public is e'@graphql({"introspection": true})';

If you already have a comment on your schema (e.g. for inflect_names), combine the keys:


_10
comment on schema public is e'@graphql({"inflect_names": true, "introspection": true})';

Why this change#

Introspection exposes your full API surface — all types, fields, and relationships — to anyone who can reach the endpoint. Disabling it by default reduces the risk of API enumeration and makes it easier to keep private schemas private.

Further reading#

2026
2025
2024
2023
2022
2021

Build in a weekend, scale to millions