import { NextRequest, NextResponse } from "next/server"; import { createSignupRecord, exchangeCodeForToken, fetchUserInfo, fetchViewer, getAppUrl, getOAuthRedirectUri, storeSignupRecord, } from "@/lib/huggingface"; import { clearOAuthCookies, clearSessionCookie, readOAuthCookies, setSessionCookie, } from "@/lib/session"; export const runtime = "nodejs"; function redirectWithAuthError(request: NextRequest, code: string) { const response = NextResponse.redirect(new URL(`/?error=${code}`, getAppUrl(request))); clearOAuthCookies(response); clearSessionCookie(response); return response; } export async function GET(request: NextRequest) { const url = new URL(request.url); const providerError = url.searchParams.get("error"); if (providerError) { return redirectWithAuthError( request, providerError === "access_denied" ? "oauth_denied" : "oauth_failed", ); } const code = url.searchParams.get("code"); const returnedState = url.searchParams.get("state"); const { state, verifier } = readOAuthCookies(request); if (!code || !returnedState || !state || returnedState !== state || !verifier) { return redirectWithAuthError(request, "oauth_state"); } try { const token = await exchangeCodeForToken({ code, codeVerifier: verifier, redirectUri: getOAuthRedirectUri(request), }); const [userInfo, viewer] = await Promise.all([ fetchUserInfo(token.access_token), fetchViewer(token.access_token), ]); const session = { id: userInfo.sub, username: userInfo.preferred_username || viewer.name, name: userInfo.name.trim() || viewer.fullname || viewer.name, email: userInfo.email ?? viewer.email, emailVerified: userInfo.email_verified ?? viewer.emailVerified, avatarUrl: userInfo.picture || viewer.avatarUrl, profileUrl: userInfo.profile || `${process.env.HF_HUB_URL ?? "https://huggingface.co"}/${viewer.name}`, website: userInfo.website ?? null, isPro: userInfo.isPro ?? viewer.isPro, registrationComplete: false, }; try { await storeSignupRecord(createSignupRecord({ session })); const response = NextResponse.redirect(new URL("/?signed_up=1", getAppUrl(request))); clearOAuthCookies(response); setSessionCookie(response, { ...session, registrationComplete: true, }); return response; } catch (error) { console.error(error); const response = NextResponse.redirect(new URL("/?error=signup_store", getAppUrl(request))); clearOAuthCookies(response); setSessionCookie(response, session); return response; } } catch (error) { console.error(error); return redirectWithAuthError(request, "oauth_exchange"); } }