fix(web): resolve display name from userInfo, not just claims (#70)

getAuthenticatedUser only read ID token claims, where `name` is often
absent, so the web app showed the user's email instead of their name
after SSO. Fetch the userInfo endpoint and resolve the display name with
the same fallback order as the vitrine (la-compagnie-maximus#80):
userInfo.name -> userInfo.username -> claims.name -> claims.username,
with the email fallback applied in the layout. Email now also prefers
userInfo over claims.

Single source of truth in auth.ts (only producer of `name`, consumed
solely by layout.tsx -> Header). layout.tsx and Header.tsx verified,
left unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
le king fu 2026-05-30 14:10:14 -04:00
parent d38ddab0f0
commit 3637879f90

View file

@ -4,16 +4,26 @@ import { logtoConfig } from './logto';
export const getAuthenticatedUser = cache(async () => {
try {
const context = await getLogtoContext(logtoConfig);
const context = await getLogtoContext(logtoConfig, { fetchUserInfo: true });
if (!context.isAuthenticated || !context.claims?.sub) {
return null;
}
const { claims, userInfo } = context;
// Mirror the vitrine's display-name resolution (la-compagnie-maximus#80):
// prefer the userInfo endpoint over ID token claims, falling back to email
// in the layout. The `name` claim is often absent from the ID token while
// present in userInfo, which is why the user saw their email instead of "Max".
return {
userId: context.claims.sub,
email: context.claims.email,
name: context.claims.name,
userId: claims.sub,
email: userInfo?.email || claims.email,
name:
userInfo?.name ||
userInfo?.username ||
claims.name ||
claims.username,
};
} catch (error) {
console.error('[auth] getLogtoContext error:', error);