| 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"); |
| } |
| } |
|
|