This commit is contained in:
2026-02-18 22:58:41 +01:00
parent b3db7cbd7b
commit 1ca76b0fec
5 changed files with 41 additions and 17 deletions

View File

@@ -170,10 +170,27 @@ export async function verifyToken(tokenSet: TokenSet): Promise<boolean> {
}
}
// Cache userinfo responses to avoid hitting the OIDC provider on every request.
// Entries expire after 5 minutes. The cache is keyed by the raw access token.
const userinfoCache = new Map<string, { user: AuthenticatedUser; expiresAt: number }>();
const USERINFO_CACHE_TTL_MS = 5 * 60 * 1000;
export async function verifyBearerToken(accessToken: string): Promise<AuthenticatedUser> {
const cached = userinfoCache.get(accessToken);
if (cached && Date.now() < cached.expiresAt) {
return cached.user;
}
const client = getOIDCClient();
const userInfo = await client.userinfo(accessToken);
let userInfo: Awaited<ReturnType<typeof client.userinfo>>;
try {
userInfo = await client.userinfo(accessToken);
} catch (err) {
// Remove any stale cache entry for this token
userinfoCache.delete(accessToken);
throw err;
}
const id = String(userInfo.sub);
const username = String(userInfo.preferred_username || userInfo.name || id);
@@ -184,5 +201,7 @@ export async function verifyBearerToken(accessToken: string): Promise<Authentica
throw new Error('Email not provided by OIDC provider');
}
return { id, username, fullName, email };
const user: AuthenticatedUser = { id, username, fullName, email };
userinfoCache.set(accessToken, { user, expiresAt: Date.now() + USERINFO_CACHE_TTL_MS });
return user;
}

View File

@@ -16,14 +16,17 @@ export async function requireAuth(
// 2. Bearer token auth (iOS / native clients)
const authHeader = req.headers.authorization;
console.log('[requireAuth] authorization header:', authHeader ? `${authHeader.slice(0, 20)}` : '(none)');
if (authHeader?.startsWith('Bearer ')) {
const accessToken = authHeader.slice(7);
try {
const user = await verifyBearerToken(accessToken);
req.user = user;
return next();
} catch {
res.status(401).json({ error: 'Unauthorized' });
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error('[requireAuth] verifyBearerToken failed:', err);
res.status(401).json({ error: `Unauthorized: ${message}` });
return;
}
}