Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import { NextRequest, NextResponse } from 'next/server'; | |
| import { cookies } from 'next/headers'; | |
| const TOKEN_ENDPOINT = 'https://huggingface.co/oauth/token'; | |
| const USERINFO_ENDPOINT = 'https://huggingface.co/oauth/userinfo'; | |
| const STATE_COOKIE = 'hf_oauth_state'; | |
| function htmlResponse(script: string) { | |
| return new NextResponse( | |
| `<!DOCTYPE html><html><body><script>${script}</script></body></html>`, | |
| { | |
| headers: { 'Content-Type': 'text/html; charset=utf-8' }, | |
| }, | |
| ); | |
| } | |
| export async function GET(request: NextRequest) { | |
| const clientId = process.env.HF_OAUTH_CLIENT_ID || process.env.NEXT_PUBLIC_HF_OAUTH_CLIENT_ID; | |
| const clientSecret = process.env.HF_OAUTH_CLIENT_SECRET; | |
| if (!clientId || !clientSecret) { | |
| return NextResponse.json({ error: 'OAuth application is not configured' }, { status: 500 }); | |
| } | |
| const { searchParams } = new URL(request.url); | |
| const code = searchParams.get('code'); | |
| const incomingState = searchParams.get('state'); | |
| const cookieStore = cookies(); | |
| const storedState = cookieStore.get(STATE_COOKIE)?.value; | |
| cookieStore.delete(STATE_COOKIE); | |
| const origin = request.nextUrl.origin; | |
| if (!code || !incomingState || !storedState || incomingState !== storedState) { | |
| const script = ` | |
| window.opener && window.opener.postMessage({ | |
| type: 'HF_OAUTH_ERROR', | |
| payload: { message: 'Invalid or expired OAuth state.' } | |
| }, '${origin}'); | |
| setTimeout(function() { window.close(); }, 100); | |
| `; | |
| return htmlResponse(script.trim()); | |
| } | |
| const redirectUri = process.env.HF_OAUTH_REDIRECT_URI || process.env.NEXT_PUBLIC_HF_OAUTH_REDIRECT_URI || `${origin}/api/auth/hf/callback`; | |
| try { | |
| const tokenResponse = await fetch(TOKEN_ENDPOINT, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/x-www-form-urlencoded', | |
| }, | |
| body: new URLSearchParams({ | |
| grant_type: 'authorization_code', | |
| code, | |
| redirect_uri: redirectUri, | |
| client_id: clientId, | |
| client_secret: clientSecret, | |
| }), | |
| }); | |
| if (!tokenResponse.ok) { | |
| const errorPayload = await tokenResponse.json().catch(() => ({})); | |
| throw new Error(errorPayload?.error_description || 'Failed to exchange code for token'); | |
| } | |
| const tokenData = await tokenResponse.json(); | |
| const accessToken = tokenData?.access_token; | |
| if (!accessToken) { | |
| throw new Error('Access token missing in response'); | |
| } | |
| const userResponse = await fetch(USERINFO_ENDPOINT, { | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| }, | |
| }); | |
| if (!userResponse.ok) { | |
| throw new Error('Failed to fetch user info'); | |
| } | |
| const profile = await userResponse.json(); | |
| const namespace = profile?.preferred_username || profile?.name || 'user'; | |
| const script = ` | |
| (function() { | |
| const target = window.opener || window.parent || window; | |
| if (target) { | |
| target.postMessage({ | |
| type: 'HF_OAUTH_SUCCESS', | |
| payload: { | |
| token: ${JSON.stringify(accessToken)}, | |
| namespace: ${JSON.stringify(namespace)}, | |
| } | |
| }, '${origin}'); | |
| } | |
| setTimeout(function() { window.close(); }, 100); | |
| })(); | |
| `; | |
| return htmlResponse(script.trim()); | |
| } catch (error: any) { | |
| const message = error?.message || 'OAuth flow failed'; | |
| const script = ` | |
| (function() { | |
| const target = window.opener || window.parent || window; | |
| if (target) { | |
| target.postMessage({ | |
| type: 'HF_OAUTH_ERROR', | |
| payload: { message: ${JSON.stringify(message)} } | |
| }, '${origin}'); | |
| } | |
| setTimeout(function() { window.close(); }, 100); | |
| })(); | |
| `; | |
| return htmlResponse(script.trim()); | |
| } | |
| } | |