fix(web): resolve display name from userInfo, not just claims (#70) #89
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/simpl-liste#89
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-70-harmonize-display-name"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #70
Problème
Après connexion SSO sur
liste.lacompagniemaximus.com, le user voyait son email au lieu de son nom ("Max"). La vitrine (lacompagniemaximus.com) affiche correctement le nom.Cause
getAuthenticatedUser()(web/src/lib/auth.ts) ne lisait quecontext.claims. Le claimnameest souvent absent de l'ID token (présent côtéuserInfo), donc le fallback retombait sur l'email.Fix (
web/src/lib/auth.ts, seul fichier modifié)getLogtoContext(logtoConfig, { fetchUserInfo: true })— récupère le userInfo endpoint.la-compagnie-maximus#80) :userInfo.name || userInfo.username || claims.name || claims.username, le|| emailfinal appliqué dans le layout (user.name || user.email || "").emailpréfère désormaisuserInfo.emailpuisclaims.email.Décisions
auth.ts(single source of truth — seul producteur dename, consommé uniquement parlayout.tsx → Header). La vitrine calculedisplayNameau point d'usage car elle renvoie les claims bruts au client via une route API ; ici l'archi server-component fait d'auth.tsle point de résolution naturel.layout.tsx: vérifié, inchangé —user.name || user.email || ""est déjà le tail|| emailde la chaîne, il reçoit maintenant le nom résolu.Header.tsx: vérifié, propuserName: stringcorrect, inchangé.Vérification
tsc --noEmit: OK (typecheck de la chaîne + optionfetchUserInfo)eslint src/lib/auth.ts: clean (0 problème sur le fichier modifié)npm test) : OK (non-régression mobile)web/a 3 erreurs pré-existantes dans d'autres fichiers (lists/[id]/page.tsx,api/lists/[id]/tasks/route.ts,ThemeToggle.tsx), hors scope de cette PR.web/.Diff : 1 fichier, +14/-4.
/pr-review — APPROVE
Summary — Correct, minimal, type-safe fix. The display-name resolution is moved to the userInfo endpoint with the ID-token claims preserved as fallback; the change is purely additive and well-scoped (1 file, +14/-4).
Verified
web/src/lib/auth.tsmodified, matching the PR body. Conventional commit +Fixes #70.tsc --noEmitpasses clean. Confirmed against the Logto types:UserInfoResponse = IdTokenClaims & {…}andIdTokenClaimsdeclaresname?,username?,email?(allNullable<string>);fetchUserInfois a valid key on thegetLogtoContextparameter subset. Every field access in the diff is real and typed.user.nameis consumed in exactly one place (layout.tsx:40,user.name || user.email || ""). The three other consumers (page.tsx,lists/[id]/page.tsx,api.ts) read onlyuser.userId. So a possibly-undefinednameis safely absorbed by the layout's|| email || ""tail — the consolidation claim holds..env. The extra userinfo call sits inside the existing try/catch (errors →null→ redirect to/auth).emailnow prefersuserInfo?.emailthenclaims.email.Non-blocking note
fetchUserInfo: truenow triggers a userinfo HTTP round-trip on everygetAuthenticatedUser()call, which includes every authenticated API request viarequireAuth()(web cookie path). Thecache()wrapper dedupes within a single request, so the cost is one extra upstream call per request — acceptable, just worth tracking if the userinfo endpoint ever becomes a latency concern.The behavioral AC (user sees "Max") remains to confirm at deploy, as noted in the PR.