Version 0.18.0 : jetons OAuth chiffrés, appelant Nest sous Node 24 #127

Merged
nicolas-fryder merged 6 commits from dev into main 2026-10-09 15:15:12 +00:00

Ce que ça livre

Les jetons OAuth de account sont chiffrés, sans condition (D-060), mineur.
Un jeton délégué (HQ) permet d'agir sur une API au nom de la personne : stocké en clair, une copie de la base suffirait à s'en servir. creerAuth pose donc account.encryptOAuthTokens, avec la clé AUTH_SECRET.
La première version (#126) ne l'activait qu'en présence d'un fournisseur délégué. Or better-auth ne déchiffre que si l'option est active, et elle vaut pour toute la table : un délégué retiré ou à moitié configuré aurait fait relire les jetons chiffrés tels quels, Microsoft compris, sans que rien ne le signale au démarrage.

  • Un jeton se lit par auth.api.getAccessToken, jamais dans la table. revoquerChezFournisseur refuse une valeur qui a la forme d'un jeton chiffré : sinon la RFC 7009 répondrait 200, et la fonction annoncerait une révocation qui n'a pas eu lieu.
  • Un jeton stocké en clair reste lisible, sauf une chaîne hexadécimale de longueur paire (un jeton Forgejo) : cette délégation est à relier.
  • Changer AUTH_SECRET rend désormais illisibles les jetons de account (cahier, §6).

Le gestionnaire Nest retrouve son appelant sous Node 24 (D-061, chasse 38), correctif.
La garde posait le principal par enterWith après un await. Sous Node 24.15, il n'atteignait pas le gestionnaire : chaque appel délégué de Nuage partait en 500 « hors requête », et l'on-behalf-of refusait faute d'assertion. Désormais, la garde retient le principal, et EqsAppelantInterceptor, monté par EqsAuthModule.forEqs, exécute le gestionnaire dans avecAppelant. poserAppelant est déprécié, et rxjs devient une dépendance pair facultative.
Le test monte une application Nest réelle interrogée par HTTP : 3 cas sur 4 échouaient avant le correctif, 4 sur 4 passent après.

Ce que les satellites ont à faire

  • Rien s'ils montent EqsAuthModule.forEqs.
  • Ne jamais lire un jeton dans account : passer par getAccessToken.
  • Relier les délégations dont le jeton stocké en clair est hexadécimal.

Vérifié / non vérifié

  • pnpm check est vert sous Node 24.15.
  • Pas revérifié sous Node 22.18. Le mécanisme (run qui englobe) ne dépend pas de la version, mais le test n'a pas été joué sous Node 22.
  • Il reste la règle ESLint sur enterWith (chasse 38).
  • Nuage (liaison HQ) attend cette version : la liaison ne doit pas partir en production avant la publication.

🤖 Generated with Claude Code

### Ce que ça livre **Les jetons OAuth de `account` sont chiffrés, sans condition (D-060), mineur.** Un jeton délégué (HQ) permet d'agir sur une API au nom de la personne : stocké en clair, une copie de la base suffirait à s'en servir. `creerAuth` pose donc `account.encryptOAuthTokens`, avec la clé `AUTH_SECRET`. La première version (#126) ne l'activait qu'en présence d'un fournisseur délégué. Or better-auth ne déchiffre que si l'option est active, et elle vaut pour toute la table : un délégué retiré ou à moitié configuré aurait fait relire les jetons chiffrés tels quels, Microsoft compris, sans que rien ne le signale au démarrage. - Un jeton se lit par `auth.api.getAccessToken`, jamais dans la table. `revoquerChezFournisseur` refuse une valeur qui a la forme d'un jeton chiffré : sinon la RFC 7009 répondrait 200, et la fonction annoncerait une révocation qui n'a pas eu lieu. - Un jeton stocké en clair reste lisible, sauf une chaîne hexadécimale de longueur paire (un jeton Forgejo) : cette délégation est à relier. - Changer `AUTH_SECRET` rend désormais illisibles les jetons de `account` (cahier, §6). **Le gestionnaire Nest retrouve son appelant sous Node 24 (D-061, chasse 38), correctif.** La garde posait le principal par `enterWith` après un `await`. Sous Node 24.15, il n'atteignait pas le gestionnaire : chaque appel délégué de Nuage partait en 500 « hors requête », et l'on-behalf-of refusait faute d'assertion. Désormais, la garde retient le principal, et `EqsAppelantInterceptor`, monté par `EqsAuthModule.forEqs`, exécute le gestionnaire dans `avecAppelant`. `poserAppelant` est déprécié, et `rxjs` devient une dépendance pair facultative. Le test monte une application Nest réelle interrogée par HTTP : 3 cas sur 4 échouaient avant le correctif, 4 sur 4 passent après. ### Ce que les satellites ont à faire - Rien s'ils montent `EqsAuthModule.forEqs`. - Ne jamais lire un jeton dans `account` : passer par `getAccessToken`. - Relier les délégations dont le jeton stocké en clair est hexadécimal. ### Vérifié / non vérifié - `pnpm check` est vert sous Node 24.15. - Pas revérifié sous Node 22.18. Le mécanisme (`run` qui englobe) ne dépend pas de la version, mais le test n'a pas été joué sous Node 22. - Il reste la règle ESLint sur `enterWith` (chasse 38). - Nuage (liaison HQ) attend cette version : la liaison ne doit pas partir en production avant la publication. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Un jeton délégué (HQ) ouvre une API au nom de la personne ; en clair dans la
table `account`, une copie de la base suffirait à s'en servir. Dès qu'un
fournisseur délégué est actif, creerAuth pose `account.encryptOAuthTokens`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
better-auth ne déchiffre que si `encryptOAuthTokens` est actif, et l'option
vaut pour toute la table `account`. Liée aux délégués, elle s'éteignait avec
le dernier retiré : `getAccessToken` rendait l'hexadécimal chiffré — Microsoft
compris —, sans rien dire au démarrage. Elle est désormais posée sans
condition (D-060).

- `revoquerChezFournisseur` refuse une valeur qui a la forme d'un chiffré
  (hexadécimal nu de 82 caractères au moins, ou enveloppe `$ba$`), sans
  appeler le fournisseur : la RFC 7009 répond 200 même pour un jeton invalide.
- Le changeset dit ce qui est vrai : un jeton stocké en clair reste lisible,
  sauf une chaîne hexadécimale paire (un jeton Forgejo), à relier ; changer
  `AUTH_SECRET` rend les jetons illisibles.
- Les tests qui relisaient l'option sont remplacés par l'aller-retour : la
  liaison jouée sur l'adaptateur mémoire, la table garde un chiffré,
  `getAccessToken` rend le jeton reçu ; et le délégué retiré, le jeton
  Microsoft chiffré reste lisible (rouge sur 90daa1d).
- Cahier §4.5 et §6, D-060.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La garde posait le principal par `AsyncLocalStorage.enterWith`, après
l'`await` de `resoudrePrincipal`. Sous Node 24.15 ce magasin reste dans la
suite de la garde : `appelantCourant()` rendait `undefined` dans le
gestionnaire, et chaque appel délégué de `@eqs/http` partait en 500
« hors requête » (relevé par nuage) ; l'assertion de l'on-behalf-of aussi.

La garde retient désormais `{ principal, assertion }` dans une WeakMap
indexée par la requête ; `EqsAppelantInterceptor`, monté en APP_INTERCEPTOR
par `EqsAuthModule`, appelle et souscrit `next.handle()` dans `avecAppelant`.
`canAccess` tourne aussi dans `avecAppelant`. `poserAppelant` reste exporté,
déprécié. `rxjs` devient un pair facultatif.

Test : une application Nest réelle interrogée par HTTP (clé API, jeton
Entra, deux requêtes concurrentes) — rouge avant sous Node 24.15, vert
après. D-061, chasse 38, cahier §4.5, changeset patch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
nicolas-fryder referenced this pull request from a commit 2026-10-12 07:57:22 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Infrastructure/eqs-platform!127
No description provided.