Repository navigation
[NestJS] Porter la route GET /api/v1/auth depuis le serveur Fastify vers server-nestjs #2225
Description
Activity
- addedtechnical debtRésoud de la dette techniqueRésoud de la dette techniquerefactorRefactor codeRefactor code
on Jun 17, 2026 - changed the title
[-][NestJS] Port POST /api/v1/auth route from Fastify server to server-nestjs[/-][+][NestJS] Porter la route POST /api/v1/auth depuis le serveur Fastify vers server-nestjs[/+]on Jun 17, 2026 - added a parent issue
on Sep 29, 2026 - changed the title
[-][NestJS] Porter la route POST /api/v1/auth depuis le serveur Fastify vers server-nestjs[/-][+][NestJS] Porter la route GET /api/v1/auth depuis le serveur Fastify vers server-nestjs[/+]on Oct 6, 2026 Convergence — qualification contre le code réel (2026-10-06)
Trois résolutions issues de la comparaison systématique du ticket avec
origin/main: le périmètre initial a été écrit avant que le moduleuser
n'existe ; deux des trois prérequis qu'il listait sont désormais portés par
l'existant, et le verbe de la route était faux.1. Le verbe est
GET, pasPOST. Le contrat partagé fait foi :// packages/shared/src/contracts/user.ts @ origin/main auth: { method: 'GET', path: `${apiPrefix}/auth`, summary: 'Login', description: 'OIDC callback to signin or signup',
Le client consomme ce contrat (
apiClient.Users.auth()dans
apps/client/src/stores/user.ts). Le corps du ticket disaitPOST: corrigé.2.
UserModuleexiste déjà.user.controller.tssert déjà
GET /api/v1/users,GET /api/v1/users/matchingetPATCH /api/v1/userset la
routelocation /api/v1/usersderouting.confpointe vers NestJS. Le ticket
demandait de créer le module : seul le endpointauthmanque. Le service
expose déjàPrismaService+EventEmitter2;toContractUserest réutilisable
pour la réponse.3. Le vrai travail est la session, pas la route. Côté legacy,
req.session.userest alimenté par la pilefastify-cookie+@fastify/session
(sessionConf: cookiesessionId, httpOnly, secure, expires 30 min) remplie
parfastify-keycloak-adapterviauserPayloadMapper(sub → id,
given_name → firstName,family_name → lastName,groups). Côté NestJS :
aucun plugin de session enregistré dansmain.ts, etAuthServicene couvre que
dso-tokenetkeycloak-jwt(headerAuthorization: Bearer). Or le client envoie
déjà le token Bearer sur toutes les routes hors liste blanche
(apps/client/src/api/xhr-client.ts). La qualification a donc tranché l'approche :- Option retenue — port du handler via le token Bearer existant :
KeycloakJwtService.validatePayloadimplémente déjà la logique métier de
logViaSession(findUnique user, upsert desadminRoleIdsfusionnant groupes
OIDC + rôles persistés +type: 'global', bitmask OR des permissions,
lastLogin). Le handler devient un@Get('auth')dans leUserController
existant qui délègue àAuthService.authenticate(ou directement à
KeycloakJwtService), complète la création du user manquant
(logViaSessioncrée avectype: 'human',validatePayloadrenvoie 401) et
retourne le user complet viatoContractUser. Aucune session Fastify à
répliquer, aucun secret partagé legacy à porter. - Option écartée — répliquer
@fastify/session: le cookie de session
legacy et le Bearer du client coexistent dans la même requête ; aligner NestJS
sur le mécanisme déjà émis par le client évite un troisième chemin
d'authentification et la synchronisation desessionSecretentre les deux
backends.
Divergence comportementale à décider pendant l'implémentation : la création à la
volée d'un user absent (legacy : upserttype: 'human'; NestJS actuel : 401).
Le respect du contrat (200 avecUserSchema+307documenté) impose de porter
la création, sinon tout premier login sur une route NestJS échoue.Le corps du ticket a été réécrit avec ce périmètre qualifié ; l'estimation
~2 j tient, l'essentiel étant l'écart create-vs-401 et la parité de réponse.- Option retenue — port du handler via le token Bearer existant :
- added a commit that references this issue
on Oct 6, 2026 - linked a pull request that will close this issuefeat(auth): router la connexion GET /api/v1/auth vers server-nestjs #2824
on Oct 6, 2026 - linked a pull request that will close this issuefeat(nginx-strangler): router la connexion /api/v1/auth vers server-nestjs #2826
on Oct 6, 2026
Description
La route
GET /api/v1/auth(login / synchronisation de session OIDC) est ladernière route du module
userservie uniquement par le legacy(
apps/server/src/resources/user/router.ts, handlerauth). La tapissant dansle
location /api/catch-all, elle maintientapps/serverdéployé pour le seulflux de connexion et empêche de solder la vague « user » du suivi
#1889.
Le module
UserModulecible existe déjà dansapps/server-nestjs/src/modules/user/et sertGET /users,GET /users/matching,PATCH /users; seul ce endpoint manque. Laqualification du 2026-10-06 (voir commentaire) a arrêté l'approche : réutiliser
le chemin d'authentification Bearer déjà émis par le client plutôt que répliquer
la pile de session Fastify du legacy.
req.session.user(rempli parfastify-keycloak-adapterviauserPayloadMapper:sub → id,given_name → firstName,family_name → lastName,groups), 401 si absent.logViaSession: find-or-create du user (création avectype: 'human',adminRoleIds: []), fusion des rôles admin (groupes OIDC ∪ rôles persistés ∪type: 'global'), mise à jourlastLogin, réponseUserSchema(200).@Get('auth')dans leUserControllerexistant, sans garde admin.Authentification via
AuthService/KeycloakJwtService(headerAuthorization: Bearerdéjà envoyé parapps/client/src/api/xhr-client.tspour toute route hors liste blanche).
KeycloakJwtService.validatePayloadcouvre déjà find-or-update, fusion desadminRoleIdset calcul du bitmask ; l'écart à combler est la création à lavolée du user absent (legacy : upsert
type: 'human'; NestJS actuel : 401).Réponse :
UserSchemaviatoContractUser(contrat déjà défini danspackages/shared/src/contracts/user.ts,method: 'GET', réponses200: UserSchema,307,500).Legacy handler :
apps/server/src/resources/user/router.ts(auth) etlogViaSessiondansapps/server/src/resources/user/business.tsContrat :
packages/shared/src/contracts/user.tsConsommateur client :
apps/client/src/stores/user.ts(
apiClient.Users.auth()), token Bearer :apps/client/src/api/xhr-client.tsAuth NestJS existante :
apps/server-nestjs/src/modules/infrastructure/auth/(
keycloak-jwt/keycloak-jwt.service.ts)Module cible :
apps/server-nestjs/src/modules/user/Suivi global : [NestJS] Modularisation de server #1889
Définition du fini
GET /api/v1/authservi parUserControlleravec parité de réponse(même session Keycloak ⇒ même
UserSchemaque le legacy)type: 'human'),pas de 401
adminRoleIdsidentiques au legacy pour les troissources de rôles (OIDC, persistés, global)
routing.conf:location = /api/v1/authversserver-nestjs, marquée vague + procédure de rollbackusersoldée) etMODULARISATION-STATUT.mdactualisé