Download src/app/api/auth/google/callback/route.ts from simikkk/test8: direct link, hf CLI and curl.
- Browser
- Download file 4.49 kB
-
https://huggingface.co/spaces/simikkk/test8/resolve/main/src/app/api/auth/google/callback/route.ts
- Command line
-
hf download hf://spaces/simikkk/test8/src/app/api/auth/google/callback/route.ts
-
curl -L -o route.ts https://huggingface.co/spaces/simikkk/test8/resolve/main/src/app/api/auth/google/callback/route.ts
4.49 kB
| import { NextRequest, NextResponse } from 'next/server'; | |
| import { withDb } from '@/lib/api-handler'; | |
| import { db } from '@/lib/db'; | |
| import { createSession, hashPassword, generateApiKey, SESSION_COOKIE_NAME } from '@/lib/auth'; | |
| import { logActivity } from '@/lib/activity'; | |
| import crypto from 'crypto'; | |
| async function handler(request: NextRequest) { | |
| try { | |
| const { searchParams } = new URL(request.url); | |
| const code = searchParams.get('code'); | |
| if (!code) { | |
| return NextResponse.redirect(new URL('/?error=no_code', request.url)); | |
| } | |
| const clientId = process.env.GOOGLE_CLIENT_ID; | |
| const clientSecret = process.env.GOOGLE_CLIENT_SECRET; | |
| const redirectUri = `${process.env.NEXT_PUBLIC_BASE_URL || ''}/api/auth/google/callback`; | |
| if (!clientId || !clientSecret) { | |
| return NextResponse.redirect(new URL('/?error=not_configured', request.url)); | |
| } | |
| // ── Exchange code for tokens ────────────────────────────────────── | |
| const tokenResponse = await fetch('https://oauth2.googleapis.com/token', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |
| body: new URLSearchParams({ | |
| code, | |
| client_id: clientId, | |
| client_secret: clientSecret, | |
| redirect_uri: redirectUri, | |
| grant_type: 'authorization_code', | |
| }), | |
| }); | |
| if (!tokenResponse.ok) { | |
| console.error('[GOOGLE_TOKEN_ERROR]', await tokenResponse.text()); | |
| return NextResponse.redirect(new URL('/?error=token_exchange_failed', request.url)); | |
| } | |
| const tokens = await tokenResponse.json() as { access_token: string }; | |
| // ── Fetch user info from Google ─────────────────────────────────── | |
| const userInfoResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', { | |
| headers: { Authorization: `Bearer ${tokens.access_token}` }, | |
| }); | |
| if (!userInfoResponse.ok) { | |
| console.error('[GOOGLE_USER_ERROR]', await userInfoResponse.text()); | |
| return NextResponse.redirect(new URL('/?error=user_fetch_failed', request.url)); | |
| } | |
| const googleUser = await userInfoResponse.json() as { | |
| email: string; | |
| name?: string; | |
| picture?: string; | |
| }; | |
| if (!googleUser.email) { | |
| return NextResponse.redirect(new URL('/?error=no_email', request.url)); | |
| } | |
| // ── Find or create user ─────────────────────────────────────────── | |
| let user = await db.user.findUnique({ where: { email: googleUser.email } }); | |
| if (!user) { | |
| const randomPw = crypto.randomBytes(32).toString('hex'); | |
| const hashedPw = await hashPassword(randomPw); | |
| const apiKey = generateApiKey(); | |
| user = await db.user.create({ | |
| data: { | |
| email: googleUser.email, | |
| name: googleUser.name || googleUser.email.split('@')[0], | |
| password: hashedPw, | |
| apiKey, | |
| plan: 'free', | |
| }, | |
| }); | |
| logActivity(user.id, 'signup', 'Account created via Google', user.email); | |
| } | |
| // ── Create session ──────────────────────────────────────────────── | |
| const token = await createSession(user.id); | |
| const forwardedProto = request.headers.get('x-forwarded-proto'); | |
| const isSecure = forwardedProto === 'https' || process.env.NODE_ENV === 'production'; | |
| const host = request.headers.get('host') || ''; | |
| const domain = host.includes('localhost') ? undefined : `.${host.split(':')[0]}`; | |
| // ── Redirect to / with cookie ───────────────────────────────────── | |
| const response = NextResponse.redirect(new URL('/', request.url)); | |
| response.cookies.set(SESSION_COOKIE_NAME, token, { | |
| httpOnly: true, | |
| secure: isSecure, | |
| sameSite: 'lax', | |
| path: '/', | |
| maxAge: 7 * 24 * 60 * 60, | |
| ...(domain ? { domain } : {}), | |
| }); | |
| logActivity(user.id, 'login', 'Logged in via Google', 'Signed in with Google OAuth'); | |
| return response; | |
| } catch (error) { | |
| console.error('[GOOGLE_CALLBACK_ERROR]', error); | |
| return NextResponse.redirect(new URL('/?error=internal', request.url)); | |
| } | |
| } | |
| export const GET = withDb(handler); |