Files
crumbs-original/src/lib/server/oauth/github.ts
T
Frederic CabassutandClaude Opus 4.6 506e6b9c87 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>
2026-03-09 01:10:37 +01:00

52 lines
1.6 KiB
TypeScript

import * as arctic from 'arctic';
import { getGithubClient } from './providers.js';
export function createGithubAuthUrl(): { url: URL; state: string } | null {
const github = getGithubClient();
if (!github) return null;
const state = arctic.generateState();
const scopes = ['user:email'];
const url = github.createAuthorizationURL(state, scopes);
return { url, state };
}
export async function validateGithubCallback(
code: string
): Promise<{ email: string; name: string; providerId: string } | null> {
const github = getGithubClient();
if (!github) return null;
const tokens = await github.validateAuthorizationCode(code);
const accessToken = tokens.accessToken();
// Fetch user profile
const userRes = await fetch('https://api.github.com/user', {
headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' }
});
if (!userRes.ok) return null;
const user = (await userRes.json()) as { id: number; login: string; name?: string; email?: string };
// GitHub may not return email in profile — fetch from emails endpoint
let email = user.email;
if (!email) {
const emailsRes = await fetch('https://api.github.com/user/emails', {
headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json' }
});
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 || undefined;
}
}
if (!email) return null;
return {
email,
name: user.name || user.login,
providerId: String(user.id)
};
}