refactor(frontend): make SessionUser fields non-null and normalize claims at boundary

This commit is contained in:
2026-07-05 23:45:18 +02:00
parent ea36816777
commit 6a49b17e38
4 changed files with 27 additions and 14 deletions
+2 -2
View File
@@ -35,10 +35,10 @@
<span
class="grid h-7 w-7 place-items-center rounded-full bg-neutral-700 text-xs font-semibold uppercase"
>
{(user.name ?? user.email ?? '?').charAt(0)}
{user.name.charAt(0)}
</span>
{/if}
<span class="hidden sm:inline">{user.name ?? user.email}</span>
<span class="hidden sm:inline">{user.name}</span>
</a>
<form method="POST" action="/logout">
<button
+20 -5
View File
@@ -70,17 +70,32 @@ export async function decodeSession(token: string | undefined): Promise<Session
}
}
function claimString(value: unknown): string | undefined {
return typeof value === 'string' && value.length > 0 ? value : undefined;
}
export function toSessionUser(claims: Record<string, unknown>, fallback?: SessionUser): SessionUser {
const sub = claimString(claims.sub) ?? fallback?.sub ?? '';
return {
sub,
name:
claimString(claims.name) ??
claimString(claims.preferred_username) ??
fallback?.name ??
claimString(claims.email) ??
sub,
email: claimString(claims.email) ?? fallback?.email ?? '',
picture: claimString(claims.picture) ?? fallback?.picture ?? ''
};
}
export async function refreshSession(session: Session): Promise<Session | null> {
if (!session.refreshToken) return null;
try {
const config = await getOidcConfig();
const tokens = await client.refreshTokenGrant(config, session.refreshToken);
const claims = tokens.claims();
return {
sub: session.sub,
name: (claims?.name as string | undefined) ?? session.name,
email: (claims?.email as string | undefined) ?? session.email,
picture: (claims?.picture as string | undefined) ?? session.picture,
...toSessionUser(tokens.claims() ?? {}, session),
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token ?? session.refreshToken,
idToken: tokens.id_token ?? session.idToken,
+3 -3
View File
@@ -1,6 +1,6 @@
export interface SessionUser {
sub: string;
name?: string;
email?: string;
picture?: string;
name: string;
email: string;
picture: string;
}
+2 -4
View File
@@ -5,6 +5,7 @@ import {
getOidcConfig,
encodeSession,
sessionCookieOptions,
toSessionUser,
type Session,
SESSION_COOKIE,
STATE_COOKIE,
@@ -44,10 +45,7 @@ export const GET: RequestHandler = async ({ url, cookies }) => {
}
const session: Session = {
sub: String(claims.sub),
name: claims.name as string | undefined,
email: claims.email as string | undefined,
picture: claims.picture as string | undefined,
...toSessionUser(claims),
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
idToken: tokens.id_token,