# Authentification

Cette page décrit l'authentification des utilisateurs de **votre** application : inscription, connexion, fournisseurs d'identité, double authentification, courriels, et les clés qui ouvrent l'API de votre projet. Elle est compatible avec le client `supabase-js` : votre application change l'adresse et la clé, pas son code. La connexion des membres à la console de Bastide est un autre sujet (voir [Compte](account.md) et [Authentification unique](sso.md)).

## Les concepts

- **Les utilisateurs** vivent dans votre base, dans le schéma `auth`. Vos politiques les reconnaissent par `auth.uid()` (voir [Sécurité des données](data-security.md)).
- **Le jeton d'accès** est un JWT du projet, signé avec son secret, valable une heure ; l'API REST le vérifie sans consulter la plateforme. Une déconnexion globale le rend inutilisable dès la requête suivante.
- **La session** dure trente jours. Son jeton de rafraîchissement tourne à chaque usage ; un jeton déjà consommé qui revient révoque la session entière, parce qu'il signale un vol.
- **Le mot de passe** compte de 12 à 256 caractères (en points de code).
- **Les chemins** sont ceux de Supabase, sous l'adresse du projet : `https://<identifiant>.donnees.bastide.app/auth/v1/…` (voir [Base de données](database.md)).

## Ce que `supabase-js` obtient

Mesuré avec `@supabase/supabase-js` 2.117.2, le paquet publié :

| Geste | Requête | Verdict |
| --- | --- | --- |
| `signUp` | `POST /auth/v1/signup` | tenu |
| `verifyOtp` | `POST /auth/v1/verify` | tenu |
| `signInWithPassword` | `POST /auth/v1/token?grant_type=password` | tenu |
| `getUser` | `GET /auth/v1/user` | tenu |
| `refreshSession` | `POST /auth/v1/token?grant_type=refresh_token` | tenu |
| `updateUser` | `PUT /auth/v1/user` | le mot de passe seul (LIM-10) |
| `signInWithOtp` | `POST /auth/v1/otp` | tenu : lien magique et code à 6 chiffres |
| `resetPasswordForEmail` | `POST /auth/v1/recover` | tenu |
| `signOut` | `POST /auth/v1/logout` | tenu, portées `global`, `local` et `others` |

Sont aussi servis : `signInWithOAuth` vers douze fournisseurs, en flux implicite comme en PKCE, et la double authentification de `supabase.auth.mfa` (TOTP et clé WebAuthn), avec les revendications `aal` et `amr` dans le jeton. Une politique peut exiger le second facteur : `(select auth.jwt() ->> 'aal') = 'aal2'`.

Ne sont pas servis :

- la connexion d'entreprise SAML (`signInWithSSO`), la liaison d'une identité (`linkIdentity`) et `/auth/v1/settings` : 404, code `chemin_auth_inconnu` (LIM-06). Une connexion d'entreprise passe par Keycloak, en OpenID Connect ;
- le changement d'adresse ou de métadonnées par `updateUser` : 400, codes `changement_d_adresse_ailleurs` et `metadonnees_non_rangees` (LIM-10). L'adresse se change par `POST /auth/v1/user/email`, avec le mot de passe puis deux confirmations ; les métadonnées vont dans une table du projet ;
- la connexion anonyme, la vérification d'un test anti-robot et la connexion web3. Les réglages « comptes anonymes » et « test anti-robot » s'enregistrent, mais aucun parcours ne les applique encore.

## Les fournisseurs d'identité

Douze fournisseurs, sous les noms de `supabase-js` : `apple`, `azure` (Microsoft Entra ID), `bitbucket`, `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `slack_oidc`, `twitch`.

1. Chez le fournisseur, déclarez l'adresse de retour : `https://<identifiant>.donnees.bastide.app/auth/v1/callback`.
2. Dans Bastide, posez l'identifiant du client et son secret (pour Apple : la clé `.p8`, l'identifiant d'équipe et celui de la clé ; pour Keycloak : l'adresse de l'instance, exigée ; pour GitLab et Entra ID : l'adresse de l'instance ou du locataire, si besoin).
3. Activez le fournisseur. Il est effectif dès l'appel, sans redémarrage. Activer exige un secret posé.

Le secret est scellé et ne se relit jamais : la console dit seulement qu'il est posé. Une adresse que le fournisseur ne dit pas vérifiée (jamais pour Entra ID ni Twitch) ne rejoint pas un compte existant.

## L'adresse du site et les redirections

- **L'adresse du site** (`SITE_URL`) est celle de votre application. Les liens des courriels y mènent.
- **Les redirections admises** (`URI_ALLOW_LIST`, vingt au plus) : chacune admet les chemins sous la sienne. Une redirection demandée hors de cette liste ramène à l'adresse du site.

Les adresses sont en `https://`, sauf `http://localhost` et `http://127.0.0.1` pour le développement.

Un lien de courriel mène toujours à une page de **votre** site, `<adresse du site>/auth/confirm?token=…&type=…`, jamais directement à la plateforme : les antivirus suivent les liens avant les personnes, et un jeton ne se consomme que sur un `POST`. Votre page lit `token` et `type`, puis le présente par un geste explicite :

| `type` | Chemin qui consomme le jeton |
| --- | --- |
| `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` |

Sans adresse de site, le seul courriel de confirmation d'inscription mène à une page servie à l'adresse du projet, dont le bouton poste le jeton.

## Les courriels d'authentification

La plateforme envoie six genres de courriels : confirmation d'adresse, avis d'inscription sur une adresse déjà confirmée, réinitialisation du mot de passe, les deux confirmations d'un changement d'adresse, et la connexion sans mot de passe (lien magique et code à 6 chiffres dans le même message). Les gabarits sont ceux de la plateforme, en français ; leur personnalisation par projet n'est pas encore disponible.

Le journal d'envoi se lit dans la carte « Courriels d'authentification » de l'écran **Authentification**, ou par `auth_email_list` : pour chaque courriel, son genre, son état (`pending`, `delivered`, `rejected`, `dead`), ses tentatives et la réponse du relais, puis les rebonds et plaintes revenus après la remise. Jamais l'adresse ni le lien. Le journal est gardé 30 jours. Les règles d'envoi (réessais, plafond horaire, liste de suppression) sont dans [Courriels](emails.md).

## Les limites horaires

Chaque projet règle ses limites de débit. Un dépassement rend 429, code `debit_depasse`, avec l'en-tête `Retry-After`.

| Réglage | Défaut | Plage |
| --- | --- | --- |
| Inscriptions par heure et par adresse IP | 30 | 1 à 300 |
| Courriels par heure et par adresse | 4 | 1 à 40 |
| Renouvellements de session par heure et par session | 30 | 1 à 300 |
| Essais sur un jeton ou un code | 5 | 1 à 10 |
| Validité du lien magique et du code, en minutes | 15 | 5 à 60 |

## Les clés du backend

| Clé | Forme | Où elle vit | Combien |
| --- | --- | --- | --- |
| Publiable | `sb_publishable_…` | Dans le code du navigateur : elle est publique par construction | Une par projet |
| Secrète | `sb_secret_…` | Côté serveur seulement | Plusieurs, révocables une à une |

- **Une clé secrète ne s'affiche qu'une fois**, à sa création : la base n'en garde qu'une empreinte salée. Frappez-en une par usage (serveur, tâche, outil) pour pouvoir en révoquer une sans casser les autres.
- **Une clé secrète présentée par un navigateur** est refusée (401, `cle_secrete_depuis_un_navigateur`), et l'analyse de posture la nomme jusqu'à sa révocation.
- **La clé publiable se remplace** en un seul geste : l'ancienne est révoquée et la nouvelle frappée dans la même transaction, pour qu'aucune lecture ne trouve le projet sans clé.
- **Les clés historiques** `anon` et `service_role` ne valent que pour un projet importé de Supabase, douze mois (LIM-09, voir [Migrer depuis Supabase](from-supabase.md)).

Frapper, remplacer et révoquer demandent le rang `admin` et un compte qui tient un second facteur. Un remplacement ou une révocation se défait dans les cinq minutes ; au-delà, frappez une nouvelle clé.

## Depuis la console

- **Authentification** : les douze fournisseurs à gauche ; celui qu'on choisit s'ouvre à droite, avec son identifiant, son secret (qu'on remplace, jamais qu'on relit) et son interrupteur. Dessous, la carte « Adresse du site et redirections » et la carte « Courriels d'authentification ».
- **Données**, section « Clés et points d'entrée » : la liste des clés, « Frapper une clé secrète », « Remplacer la clé publiable… » et « Révoquer » sur chaque clé secrète. Un dialogue nomme la clé et l'effet avant d'agir.

## Par un agent, la ligne de commande ou l'API

| Geste | Outil MCP | Ligne de commande |
| --- | --- | --- |
| Lire les réglages | `backend_auth_read` | `bastide backend auth read` |
| Régler l'authentification | `backend_auth_configure` | `bastide backend auth configure` |
| Régler un fournisseur | `backend_auth_provider_configure` | `bastide backend auth_provider configure` |
| Lire le journal des courriels | `auth_email_list` | `bastide auth_email list` |
| Lire les clés | `backend_read` | `bastide backend read` |
| Remplacer la clé publiable | `backend_key_replace` | `bastide backend key replace` |
| Révoquer une clé secrète | `backend_key_revoke` | `bastide backend key revoke` |
| Frapper une clé secrète | aucun | `bastide backend key create` |

Frapper une clé secrète n'a pas d'outil MCP : aucun outil ne rend la valeur d'un secret. Une personne la frappe depuis la console, la ligne de commande ou l'API (`POST /v1/projects/{projectId}/backend/keys`).

Régler l'adresse du site et les limites (`PATCH /v1/projects/{projectId}/backend/auth`) ; un champ absent reste tel quel :

```json
{
  "projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "urlDuSite": "https://www.exemple.fr",
  "redirectionsAdmises": ["https://www.exemple.fr/compte", "http://localhost:3000"],
  "inscriptionsParHeureParIp": 60,
  "idempotencyKey": "auth-site-2026-10-28"
}
```

La réponse porte un `undoToken` : `action_undo` défait le réglage dans les cinq minutes.

Activer GitHub (`PUT /v1/projects/{projectId}/backend/auth/providers`) :

```json
{
  "projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
  "fournisseur": "github",
  "identifiantClient": "Iv1.0123456789abcdef",
  "secret": "<secret du client OAuth>",
  "actif": true,
  "idempotencyKey": "auth-github-2026-10-28"
}
```

Ces écritures ne sont pas ouvertes aux comptes de service. Toutes refusent un projet sans base.

## Erreurs fréquentes

- **429 `debit_depasse`** : une limite horaire est atteinte ; attendez `Retry-After`, ou relevez la limite.
- **401 `cle_refusee` ou `cle_absente`** : la clé manque, est révoquée, ou n'est pas celle du projet.
- **401 `cle_secrete_depuis_un_navigateur`** : utilisez la clé publiable dans le navigateur, et révoquez la clé secrète exposée.
- **404 `chemin_auth_inconnu`** : le geste n'est pas servi (SAML, `linkIdentity`, `/settings`).
- **Le lien du courriel ramène à l'accueil** : la redirection demandée n'est pas dans les redirections admises.
- **Aucun courriel reçu** : lisez le journal d'envoi ; l'adresse a pu être suspendue après un rebond (voir [Courriels](emails.md)).

## Voir aussi

- [Sécurité des données](data-security.md), [Courriels](emails.md), [Base de données](database.md), [Migrer depuis Supabase](from-supabase.md)
- Référence : [backend.auth.configure](../reference/operations/backend.auth.configure.md), [backend.auth_provider.configure](../reference/operations/backend.auth_provider.configure.md), [auth_email.list](../reference/operations/auth_email.list.md), [backend.key.create](../reference/operations/backend.key.create.md)
