forked from mirror/crumbs-original
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>
52 lines
1.6 KiB
TypeScript
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)
|
|
};
|
|
}
|