import { randomBytes } from 'node:crypto' import { githubOAuthUrl } from '#server/utils/github-app' import { sessionConfig } from '#server/utils/server-session' interface OAuthFlowData { state: string installationId: number } /** * Begin GitHub user-to-server OAuth to prove the connecting user administers * the installation they're about to bind a tangled handle to. The random * `state` is sealed into a short-lived cookie and verified in the callback. */ export default defineEventHandler(async event => { const query = getQuery(event) const raw = query.installationId if (typeof raw !== 'string' || !/^\d+$/.test(raw)) { throw createError({ statusCode: 400, statusMessage: 'installationId is required and must be numeric' }) } const installationId = Number(raw) const state = randomBytes(16).toString('base64url') const flow = await useSession(event, { ...sessionConfig(), name: 'synchub-gh-oauth', maxAge: 10 * 60, }) await flow.update({ state, installationId }) const { url } = useRuntimeConfig().public const redirectUri = `${url.replace(/\/$/, '')}/api/github/oauth/callback` await sendRedirect(event, githubOAuthUrl({ state, redirectUri }), 302) })