Authentication
This page covers authentication for the users of your application: sign-up, sign-in, identity providers, two-factor authentication, emails, and the keys that open your project's API. It is compatible with the supabase-js client: your application changes the address and the key, not its code. Members signing in to the Bastide console is a different topic (see Account and Single sign-on).
Concepts
- Users live in your database, in the
authschema. Your policies recognise them withauth.uid()(see Data security). - The access token is a project JWT, signed with the project's secret, valid for one hour; the REST API checks it without calling the platform. A global sign-out makes it unusable from the next request.
- The session lasts thirty days. Its refresh token rotates on every use; an already consumed token that comes back revokes the whole session, because it signals theft.
- The password is 12 to 256 characters long (in code points).
- The paths are Supabase's, under the project address:
https://<identifier>.donnees.bastide.app/auth/v1/…(see Database).
What supabase-js gets
Measured with @supabase/supabase-js 2.117.2, the published package:
| Call | Request | Verdict |
|---|---|---|
signUp | POST /auth/v1/signup | works |
verifyOtp | POST /auth/v1/verify | works |
signInWithPassword | POST /auth/v1/token?grant_type=password | works |
getUser | GET /auth/v1/user | works |
refreshSession | POST /auth/v1/token?grant_type=refresh_token | works |
updateUser | PUT /auth/v1/user | password only (LIM-10) |
signInWithOtp | POST /auth/v1/otp | works: magic link and 6-digit code |
resetPasswordForEmail | POST /auth/v1/recover | works |
signOut | POST /auth/v1/logout | works, scopes global, local and others |
Also served: signInWithOAuth to twelve providers, in implicit and PKCE flows, and the two-factor authentication of supabase.auth.mfa (TOTP and WebAuthn key), with the aal and amr claims in the token. A policy can require the second factor: (select auth.jwt() ->> 'aal') = 'aal2'.
Not served:
- enterprise SAML sign-in (
signInWithSSO), identity linking (linkIdentity) and/auth/v1/settings: 404, codechemin_auth_inconnu(LIM-06). Enterprise sign-in goes through Keycloak, over OpenID Connect; - changing the address or metadata through
updateUser: 400, codeschangement_d_adresse_ailleursandmetadonnees_non_rangees(LIM-10). The address is changed withPOST /auth/v1/user/email, with the password then two confirmations; metadata belongs in a project table; - anonymous sign-in, anti-bot challenge verification and web3 sign-in. The "anonymous accounts" and "anti-bot challenge" settings are stored, but no flow applies them yet.
Identity providers
Twelve providers, under their supabase-js names: apple, azure (Microsoft Entra ID), bitbucket, discord, facebook, github, gitlab, google, keycloak, linkedin_oidc, slack_oidc, twitch.
- At the provider, register the callback address:
https://<identifier>.donnees.bastide.app/auth/v1/callback. - In Bastide, set the client identifier and its secret (for Apple: the
.p8key, the team identifier and the key identifier; for Keycloak: the instance address, required; for GitLab and Entra ID: the instance or tenant address, if needed). - Enable the provider. It takes effect on the call, with no restart. Enabling requires a secret to be set.
The secret is sealed and never read back: the console only says that it is set. An address the provider does not report as verified (never for Entra ID or Twitch) does not join an existing account.
Site address and redirects
- The site address (
SITE_URL) is your application's. Email links lead there. - Allowed redirects (
URI_ALLOW_LIST, twenty at most): each one allows the paths beneath it. A redirect requested outside this list falls back to the site address.
Addresses use https://, except http://localhost and http://127.0.0.1 for development.
An email link always leads to a page on your site, <site address>/auth/confirm?token=…&type=…, never straight to the platform: antivirus scanners follow links before people do, and a token is only consumed by a POST. Your page reads token and type, then presents it on an explicit action:
type | Path that consumes the token |
|---|---|
signup | POST /auth/v1/verify |
recovery | POST /auth/v1/reset |
magiclink | POST /auth/v1/magiclink/verify |
email_change_current | POST /auth/v1/user/email/confirm-old |
email_change_new | POST /auth/v1/user/email/confirm-new |
Without a site address, the sign-up confirmation email alone leads to a page served at the project address, whose button posts the token.
Authentication emails
The platform sends six kinds of email: address confirmation, a notice of sign-up on an already confirmed address, password reset, the two confirmations of an address change, and passwordless sign-in (magic link and 6-digit code in the same message). Templates are the platform's, in French; per-project customisation is not available yet.
The sending log is read in the « Courriels d'authentification » (authentication emails) card of the Authentification (Authentication) screen, or with auth_email_list: for each email, its kind, its state (pending, delivered, rejected, dead), its attempts and the relay's answer, then the bounces and complaints that came back after delivery. Never the address or the link. The log is kept 30 days. Sending rules (retries, hourly cap, suppression list) are in Emails.
Hourly limits
Each project sets its rate limits. Going over returns 429, code debit_depasse, with a Retry-After header.
| Setting | Default | Range |
|---|---|---|
| Sign-ups per hour per IP address | 30 | 1 to 300 |
| Emails per hour per address | 4 | 1 to 40 |
| Session refreshes per hour per session | 30 | 1 to 300 |
| Attempts on a token or code | 5 | 1 to 10 |
| Magic link and code validity, in minutes | 15 | 5 to 60 |
Backend keys
| Key | Form | Where it lives | How many |
|---|---|---|---|
| Publishable | sb_publishable_… | In browser code: it is public by design | One per project |
| Secret | sb_secret_… | Server side only | Several, revocable one by one |
- A secret key is shown once, when it is created: the database keeps only a salted hash. Issue one per use (server, job, tool) so you can revoke one without breaking the others.
- A secret key presented by a browser is refused (401,
cle_secrete_depuis_un_navigateur), and the posture analysis names it until it is revoked. - The publishable key is replaced in a single step: the old one is revoked and the new one issued in the same transaction, so no read ever finds the project without a key.
- The legacy keys
anonandservice_roleonly work for a project imported from Supabase, for twelve months (LIM-09, see Migrate from Supabase).
Issuing, replacing and revoking require the admin rank and an account holding a second factor. A replacement or a revocation can be undone within five minutes; after that, issue a new key.
From the console
- Authentification: the twelve providers on the left; the one you pick opens on the right, with its identifier, its secret (replaced, never read back) and its switch. Below, the « Adresse du site et redirections » (site address and redirects) card and the « Courriels d'authentification » card.
- Données (Data), section « Clés et points d'entrée » (keys and endpoints): the key list, « Frapper une clé secrète » (issue a secret key), « Remplacer la clé publiable… » (replace the publishable key) and « Révoquer » (revoke) on each secret key. A dialog names the key and the effect before acting.
Through an agent, the command line or the API
| Action | MCP tool | Command line |
|---|---|---|
| Read the settings | backend_auth_read | bastide backend auth read |
| Configure authentication | backend_auth_configure | bastide backend auth configure |
| Configure a provider | backend_auth_provider_configure | bastide backend auth_provider configure |
| Read the email log | auth_email_list | bastide auth_email list |
| Read the keys | backend_read | bastide backend read |
| Replace the publishable key | backend_key_replace | bastide backend key replace |
| Revoke a secret key | backend_key_revoke | bastide backend key revoke |
| Issue a secret key | none | bastide backend key create |
Issuing a secret key has no MCP tool: no tool returns the value of a secret. A person issues it from the console, the command line or the API (POST /v1/projects/{projectId}/backend/keys).
Set the site address and limits (PATCH /v1/projects/{projectId}/backend/auth); an absent field stays as it is:
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"urlDuSite": "https://www.example.com",
"redirectionsAdmises": ["https://www.example.com/account", "http://localhost:3000"],
"inscriptionsParHeureParIp": 60,
"idempotencyKey": "auth-site-2026-10-28"
}
The response carries an undoToken: action_undo reverts the setting within five minutes.
Enable GitHub (PUT /v1/projects/{projectId}/backend/auth/providers):
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"fournisseur": "github",
"identifiantClient": "Iv1.0123456789abcdef",
"secret": "<OAuth client secret>",
"actif": true,
"idempotencyKey": "auth-github-2026-10-28"
}
These writes are not open to service accounts. All of them refuse a project without a database.
Common errors
- **429
debit_depasse**: an hourly limit was reached; wait forRetry-After, or raise the limit. - **401
cle_refuseeorcle_absente**: the key is missing, revoked, or not this project's. - **401
cle_secrete_depuis_un_navigateur**: use the publishable key in the browser, and revoke the exposed secret key. - **404
chemin_auth_inconnu**: the call is not served (SAML,linkIdentity,/settings). - The email link lands on the home page: the requested redirect is not among the allowed redirects.
- No email arrives: read the sending log; the address may have been suspended after a bounce (see Emails).