Changelog

New updates and product improvements

undefined RSS

For the past six months we've been tracking a steady increase in coordinated abuse of Supabase's free-tier email infrastructure. Bad actors were standing up free Supabase projects, rewriting the auth email templates with phishing content, and then triggering signup or password-reset flows against arbitrary email addresses to deliver those phishing emails from our SMTP infrastructure to people who had no relationship with Supabase.

We rolled out increasingly aggressive rate limits on outbound auth emails. We deployed keyword blocklists to catch the most common phishing payloads. We built automated detection that flagged suspicious template content and disabled offending projects. Each one was met with a workaround within days if not hours.

To our knowledge Supabase was the only auth provider that offers both a hosted email service and fully customizable email templates on free tier. Obviously this combination is what made us a uniquely attractive target.

All of this is to say we tried hard to ship changes that wouldn't affect legitimate users. But the abusive accounts — while likely just a handful of individuals — given the scale of their abuse, were responsible for the bulk of spam leaving our infrastructure, and we've reached the point where the volume risks having our email server blacklisted entirely.

What's changing#

Starting today Wednesday, 3 June 2026, new free-tier projects using Supabase's default email provider will no longer be able to modify their auth email templates. The default templates — confirmation, password reset, magic link, etc. — will be used as-is.

Who's affected#

Existing free-tier projects keep their current email templates exactly as they are. Nothing changes for projects created before 3 June 2026. Paid plans (Pro and above) are not affected. Template customization continues to work as it does today. Free-tier projects that configure their own SMTP provider can continue to customize templates freely. The restriction only applies when sending through Supabase's default SMTP.

If you're starting a new free-tier project and need branded auth emails, you can configure your own SMTP provider (Resend, Postmark, SendGrid, Amazon SES, etc.) in your project's auth settings — once enabled, you can customize your templates as before.

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).

2026
2025
2024
2023
2022
2021

Build in a weekend, scale to millions