/** * GET /api/integrations/calendar/callback * Google OAuth callback — exchanges code for tokens and persists them. */ import { NextRequest, NextResponse } from 'next/server' import prisma from '@/lib/prisma' const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token' export async function GET(req: NextRequest) { const url = new URL(req.url) const code = url.searchParams.get('code') const userId = url.searchParams.get('state') const error = url.searchParams.get('error') if (error || !code || !userId) { return NextResponse.redirect( `${url.origin}/settings/integrations?error=calendar_auth_failed`, ) } const clientId = process.env.GOOGLE_CALENDAR_CLIENT_ID || process.env.AUTH_GOOGLE_ID || '' const clientSecret = process.env.GOOGLE_CALENDAR_CLIENT_SECRET || process.env.AUTH_GOOGLE_SECRET || '' const redirectUri = `${url.origin}/api/integrations/calendar/callback` const tokenRes = await fetch(GOOGLE_TOKEN_URL, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: clientId, client_secret: clientSecret, code, redirect_uri: redirectUri, grant_type: 'authorization_code', }), }) const tokenData = await tokenRes.json() if (!tokenData.access_token) { return NextResponse.redirect( `${url.origin}/settings/integrations?error=calendar_token_failed`, ) } // Persist tokens in UserAISettings.integrationTokens const aiSettings = await prisma.userAISettings.findUnique({ where: { userId }, select: { integrationTokens: true }, }) const meta = typeof aiSettings?.integrationTokens === 'string' ? JSON.parse(aiSettings.integrationTokens) : (aiSettings?.integrationTokens as Record | null) ?? {} meta.calendarAccessToken = tokenData.access_token if (tokenData.refresh_token) { meta.calendarRefreshToken = tokenData.refresh_token } await prisma.userAISettings.upsert({ where: { userId }, update: { integrationTokens: JSON.stringify(meta) }, create: { userId, integrationTokens: JSON.stringify(meta) }, }) return NextResponse.redirect(`${url.origin}/settings/integrations?connected=calendar`) }