import { NextRequest, NextResponse } from "next/server"; import { exchangeCodeForTokens } from "@/lib/tiktok"; import { prisma } from "@/lib/prisma"; export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); const code = searchParams.get("code"); const state = searchParams.get("state"); const error = searchParams.get("error"); if (error || !code || !state) { return NextResponse.redirect(new URL("/tiktok?error=access_denied", request.url)); } try { // userId stocké dans le record PKCE lors du /connect (pas besoin de session) const pkceRecord = await prisma.tikTokPKCE.findUnique({ where: { state } }); if (!pkceRecord) { return NextResponse.redirect(new URL("/tiktok?error=missing_verifier", request.url)); } await prisma.tikTokPKCE.delete({ where: { state } }); const { userId, codeVerifier } = pkceRecord; console.log("[TikTok callback] codeVerifier from DB:", codeVerifier); console.log("[TikTok callback] code from TikTok:", code); const tokens = await exchangeCodeForTokens(code, codeVerifier); const expiresAt = new Date(Date.now() + tokens.expires_in * 1000); await prisma.tikTokToken.upsert({ where: { userId }, create: { userId, openId: tokens.open_id, accessToken: tokens.access_token, refreshToken: tokens.refresh_token, expiresAt }, update: { openId: tokens.open_id, accessToken: tokens.access_token, refreshToken: tokens.refresh_token, expiresAt }, }); const existing = await prisma.trackedAccount.findFirst({ where: { userId, platform: "tiktok" } }); if (!existing) { await prisma.trackedAccount.create({ data: { userId, platform: "tiktok", username: tokens.open_id, accountId: tokens.open_id }, }); } return NextResponse.redirect(new URL("/tiktok?connected=1", request.url)); } catch (err) { console.error("[TikTok callback error]", err); return NextResponse.redirect(new URL("/tiktok?error=token_exchange", request.url)); } }