
# Sessions

Lorsqu'un utilisateur s'authentifie, Sovrium émet une **session gérée côté serveur** (un cookie `httpOnly` adossé à une ligne de la table `auth.session`). Les sessions sont inspectables, listables et révocables via l'API d'authentification et — pour les applications multi-locataires — augmentées par une **API de session à périmètre actif** qui permet à un utilisateur de choisir l'affectation actuellement en contexte.

## Configuration des sessions

Le comportement central des sessions (durée de vie, fenêtre de rafraîchissement) est géré au **niveau du serveur Better Auth**, pas dans le schéma de l'application. Il n'y a pas de bloc de configuration `auth.session`.

```yaml
auth:
  strategies:
    - type: emailAndPassword
  # Session lifetime/refresh are Better Auth server defaults — not schema fields.
```

| Préoccupation                              | Où elle réside                                                                               |
| ------------------------------------------ | -------------------------------------------------------------------------------------------- |
| Durée de vie / rafraîchissement de session | Valeurs par défaut du serveur Better Auth (non exposées dans `app.auth`).                    |
| Signature & chiffrement                    | Variable d'environnement `AUTH_SECRET`. Voir [Variables d'environnement](/fr/docs/env-vars). |
| Sécurité du cookie                         | Cookies `secure` en production ; dérivés de `BASE_URL` / `NODE_ENV`.                         |

:::callout
La rotation de `AUTH_SECRET` invalide toutes les sessions actives — tous les utilisateurs sont déconnectés. Traitez-le comme un identifiant et effectuez sa rotation de manière réfléchie. Voir [Renforcement de la sécurité](/fr/docs/security-hardening).
:::

## Inspecter & terminer des sessions

Les points de terminaison suivants sont montés automatiquement lorsque `auth` est configuré.

| Méthode | Point de terminaison              | Rôle                                                                     |
| ------- | --------------------------------- | ------------------------------------------------------------------------ |
| `GET`   | `/api/auth/get-session`           | Renvoie la session et l'utilisateur courants, ou un corps null si aucun. |
| `GET`   | `/api/auth/list-sessions`         | Liste toutes les sessions actives de l'utilisateur authentifié.          |
| `POST`  | `/api/auth/sign-out`              | Invalide la session courante (idempotent — toujours `200`).              |
| `POST`  | `/api/auth/revoke-session`        | Révoque une session spécifique par son id.                               |
| `POST`  | `/api/auth/revoke-other-sessions` | Révoque toutes les sessions sauf la session courante.                    |

Comportements à noter :

- `get-session` renvoie un **corps null** (et non une erreur) lorsqu'on n'est pas authentifié ou après la déconnexion, de sorte qu'un client peut l'interroger en toute sécurité pour afficher l'état d'authentification.
- `list-sessions` est **isolé par session** — un utilisateur ne voit jamais que ses propres sessions, chacune avec `id`, `userId`, horodatages de création et d'expiration.
- `sign-out` est **idempotent** : l'appeler sans session, ou de manière répétée, renvoie toujours `200`.

## Sessions à périmètre actif (multi-locataire)

Les applications qui cloisonnent les données par locataire utilisent la jonction `user_access` : un utilisateur peut avoir plusieurs lignes d'accès pour la même table (par ex. un directeur financier à temps partagé affecté à trois entreprises clientes). L'**API de session à périmètre actif** permet à cet utilisateur de choisir l'affectation actuellement active, persistée dans un cookie par table et résolue par `$currentUser.activeAssignment`.

D'abord, déclarez les tables de périmètre :

```yaml
auth:
  strategies:
    - type: emailAndPassword
  roles:
    - name: customer-admin
  scopeTables: [clients]
  landingPath: /portal
  # No extra config — active-scope endpoints auto-mount for every scopeTables entry.
```

| Propriété     | Description                                                                                                                                                                                                                                  |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scopeTables` | Tableau de slugs de table (issus de `app.tables[].name`) que les lignes `user_access` peuvent référencer. Non vide ; les entrées doivent être des identifiants slug valides ; sans doublons. Validé contre `app.tables[].name` au démarrage. |

Le moteur monte ensuite automatiquement ces points de terminaison pour chaque entrée de `scopeTables` :

| Méthode  | Chemin                                 | Comportement                                                                                                                                                             |
| -------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST`   | `/api/session/active-scope/:tableSlug` | Corps `{ recordId }`. Définit le cookie de périmètre actif lorsque `recordId` figure dans le `user_access` de l'utilisateur ; renvoie `403` sinon (aucun cookie défini). |
| `GET`    | `/api/session/active-scope/:tableSlug` | Renvoie `{ tableSlug, recordId }` depuis le cookie, ou `null` lorsqu'il n'est pas défini.                                                                                |
| `DELETE` | `/api/session/active-scope/:tableSlug` | Efface le cookie (renvoie `204`).                                                                                                                                        |

Un `:tableSlug` absent de `scopeTables` renvoie `404`.

### Modèle de sécurité

Le cookie de périmètre actif est nommé `sovrium_active_assignment_<tableSlug>` (un par table de périmètre).

1. **Attributs du cookie** — `httpOnly`, `sameSite=lax`, et `secure` en production. Non lisible par le JavaScript client.
2. **Toute écriture est validée côté serveur** — `POST` vérifie que le `recordId` figure dans les lignes `user_access` de l'utilisateur pour ce slug. Les écritures hors périmètre renvoient `403` sans changement d'état.
3. **Toute lecture est validée côté serveur** — lors de la résolution de `$currentUser.activeAssignment`, le moteur revérifie le cookie contre `user_access`. Les valeurs falsifiées, obsolètes ou désormais révoquées sont écartées et le résolveur se replie sur le premier enregistrement accessible de l'utilisateur.

:::callout
**Inviolable par construction.** Un utilisateur ne peut pas modifier le cookie pour atteindre un enregistrement hors de ses affectations — la valeur est revalidée contre `user_access` à chaque requête, à la fois lors de sa définition et de sa lecture. Cela rend le changement de contexte sûr sans nouvelle authentification.
:::

`$currentUser.activeAssignment` est consommable dans les prédicats `dataSource.filter` et les clauses `when` de permission au niveau de la ligne, de sorte que chaque vue liée à une affectation se rafraîchit automatiquement lorsque le périmètre actif change. Le jeton associé `$currentUser.assignments.<table>` (l'ensemble complet des affectations d'un utilisateur) est traité dans [Atterrissage après connexion](/fr/docs/auth-post-login).

## Pages associées

- [Présentation de l'authentification](/fr/docs/auth-overview) — activer l'authentification et le bloc `auth`.
- [Atterrissage après connexion](/fr/docs/auth-post-login) — interpolation `$currentUser.assignments` et atterrissage par rôle.
- [Permissions de table](/fr/docs/table-permissions) — prédicats `when` au niveau de la ligne qui consomment `$currentUser`.
- [Renforcement de la sécurité](/fr/docs/security-hardening) — rotation de `AUTH_SECRET` et renforcement des cookies.
