mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-13 04:06:57 +02:00
fix: resolve type errors in OAuth and API utils
Fix null vs undefined in GitHub OAuth, use arctic's createAuthorizationURLWithPKCE for OIDC, loosen api-utils type signature to avoid SvelteKit route-specific generics, add @types/zxcvbn. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Fred Cabassut
co-authored by
Claude Opus 4.6
parent
333bd4912d
commit
506e6b9c87
@@ -1,11 +1,15 @@
|
||||
import { error, type RequestEvent } from '@sveltejs/kit';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export function getUserId(event: RequestEvent): number {
|
||||
type EventWithLocals = {
|
||||
locals: App.Locals;
|
||||
};
|
||||
|
||||
export function getUserId(event: EventWithLocals): number {
|
||||
if (!event.locals.user) throw error(401, 'Unauthorized');
|
||||
return event.locals.user.id;
|
||||
}
|
||||
|
||||
export function requireAdmin(event: RequestEvent) {
|
||||
export function requireAdmin(event: EventWithLocals) {
|
||||
const user = event.locals.user;
|
||||
if (!user || user.role !== 'admin') throw error(403, 'Forbidden');
|
||||
return user;
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function validateGithubCallback(
|
||||
if (emailsRes.ok) {
|
||||
const emails = (await emailsRes.json()) as { email: string; primary: boolean; verified: boolean }[];
|
||||
const primary = emails.find((e) => e.primary && e.verified);
|
||||
email = primary?.email || emails.find((e) => e.verified)?.email || null;
|
||||
email = primary?.email || emails.find((e) => e.verified)?.email || undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,18 +53,15 @@ export async function createOidcAuthUrl(): Promise<{ url: URL; state: string; co
|
||||
|
||||
const state = arctic.generateState();
|
||||
const codeVerifier = arctic.generateCodeVerifier();
|
||||
const scopes = ['openid', 'profile', 'email'];
|
||||
|
||||
const url = new URL(oidcConfig.authorizationEndpoint);
|
||||
url.searchParams.set('response_type', 'code');
|
||||
url.searchParams.set('client_id', getOidcEnv().clientId);
|
||||
url.searchParams.set('redirect_uri', `${getBaseUrl()}/api/auth/oauth/oidc/callback`);
|
||||
url.searchParams.set('state', state);
|
||||
url.searchParams.set('scope', 'openid profile email');
|
||||
|
||||
// PKCE
|
||||
const codeChallenge = await arctic.generateCodeChallenge(codeVerifier);
|
||||
url.searchParams.set('code_challenge', codeChallenge);
|
||||
url.searchParams.set('code_challenge_method', 'S256');
|
||||
const url = client.createAuthorizationURLWithPKCE(
|
||||
oidcConfig.authorizationEndpoint,
|
||||
state,
|
||||
arctic.CodeChallengeMethod.S256,
|
||||
codeVerifier,
|
||||
scopes
|
||||
);
|
||||
|
||||
return { url, state, codeVerifier };
|
||||
}
|
||||
@@ -76,34 +73,16 @@ export async function validateOidcCallback(
|
||||
const client = await ensureOidcClient();
|
||||
if (!client || !oidcConfig) return null;
|
||||
|
||||
const env = getOidcEnv();
|
||||
const redirectURI = `${getBaseUrl()}/api/auth/oauth/oidc/callback`;
|
||||
|
||||
// Exchange code for tokens
|
||||
const body = new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
const tokens = await client.validateAuthorizationCode(
|
||||
oidcConfig.tokenEndpoint,
|
||||
code,
|
||||
redirect_uri: redirectURI,
|
||||
client_id: env.clientId,
|
||||
client_secret: env.clientSecret,
|
||||
code_verifier: codeVerifier
|
||||
});
|
||||
|
||||
const tokenRes = await fetch(oidcConfig.tokenEndpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: body.toString()
|
||||
});
|
||||
if (!tokenRes.ok) return null;
|
||||
|
||||
const tokenData = (await tokenRes.json()) as {
|
||||
access_token: string;
|
||||
id_token?: string;
|
||||
};
|
||||
codeVerifier
|
||||
);
|
||||
|
||||
// Try to decode ID token first
|
||||
if (tokenData.id_token) {
|
||||
const claims = arctic.decodeIdToken(tokenData.id_token) as {
|
||||
const idToken = tokens.idToken();
|
||||
if (idToken) {
|
||||
const claims = arctic.decodeIdToken(idToken) as {
|
||||
sub: string;
|
||||
email?: string;
|
||||
name?: string;
|
||||
@@ -118,8 +97,9 @@ export async function validateOidcCallback(
|
||||
}
|
||||
|
||||
// Fallback to userinfo endpoint
|
||||
const accessToken = tokens.accessToken();
|
||||
const userRes = await fetch(oidcConfig.userinfoEndpoint, {
|
||||
headers: { Authorization: `Bearer ${tokenData.access_token}` }
|
||||
headers: { Authorization: `Bearer ${accessToken}` }
|
||||
});
|
||||
if (!userRes.ok) return null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user