import { NextRequest, NextResponse } from "next/server"; import { eq } from "drizzle-orm"; import { db } from "@/lib/db"; import { stripeAccounts } from "@/lib/schema"; import { getUserFromSession } from "@/lib/auth/get-user"; type StripeOAuthResponse = { access_token: string; refresh_token: string; stripe_user_id: string; scope: string; }; export async function GET(req: NextRequest) { const user = await getUserFromSession(); if (!user) { return NextResponse.redirect( new URL("/login", process.env.APP_URL) ); } const { searchParams } = new URL(req.url); const code = searchParams.get("code"); const error = searchParams.get("error"); if (error) { console.error("Stripe OAuth error:", error); return NextResponse.redirect( new URL( "/connect/stripe?error=oauth_failed", process.env.APP_URL ) ); } if (!code) { return NextResponse.json( { error: "Missing OAuth code" }, { status: 400 } ); } // -------------------------------------------------- // Exchange OAuth code for Stripe account // -------------------------------------------------- const tokenRes = await fetch("https://connect.stripe.com/oauth/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", code, client_secret: process.env.STRIPE_SECRET_KEY!, }), }); if (!tokenRes.ok) { const text = await tokenRes.text(); console.error("Stripe token exchange failed:", text); return NextResponse.redirect( new URL( "/connect/stripe?error=token_exchange_failed", process.env.APP_URL ) ); } const data = (await tokenRes.json()) as StripeOAuthResponse; const stripeAccountId = data.stripe_user_id; // -------------------------------------------------- // Check for existing Stripe account connection // -------------------------------------------------- const existing = await db .select() .from(stripeAccounts) .where(eq(stripeAccounts.stripeAccountId, stripeAccountId)) .limit(1); if (existing.length > 0) { const record = existing[0]; // Same user → idempotent success if (record.userId === user.id) { console.log("Stripe already connected for this user", { stripeAccountId, userId: user.id, }); return NextResponse.redirect( new URL("/connect/stripe/success", process.env.APP_URL) ); } // Different user → block console.warn("Stripe account already linked to another user", { stripeAccountId, existingUserId: record.userId, currentUserId: user.id, }); return NextResponse.redirect( new URL( "/connect/stripe?error=already_connected", process.env.APP_URL ) ); } // -------------------------------------------------- // Insert new Stripe connection // -------------------------------------------------- await db .insert(stripeAccounts) .values({ userId: user.id, stripeAccountId: data.stripe_user_id, }) .onConflictDoUpdate({ target: stripeAccounts.userId, set: { stripeAccountId: data.stripe_user_id, }, }); console.log("Stripe OAuth connected", { stripeAccountId, userId: user.id, scope: data.scope, }); return NextResponse.redirect( new URL("/connect/stripe/success", process.env.APP_URL) ); }