juntekim.com/stripe_to_invoice/app/api/stripe/callback/route.ts
2026-02-01 20:03:08 +00:00

85 lines
2.1 KiB
TypeScript

import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
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.NEXT_PUBLIC_BASE_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.NEXT_PUBLIC_BASE_URL
)
);
}
if (!code) {
return NextResponse.json(
{ error: "Missing OAuth code" },
{ status: 400 }
);
}
// Exchange code for access token
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.NEXT_PUBLIC_BASE_URL
)
);
}
const data = (await tokenRes.json()) as StripeOAuthResponse;
// ✅ THIS IS THE MISSING PIECE
await db.insert(stripeAccounts).values({
userId: user.id,
stripeAccountId: data.stripe_user_id,
});
console.log("Stripe OAuth success", {
stripe_account_id: data.stripe_user_id,
scope: data.scope,
});
return NextResponse.redirect(
new URL("/connect/stripe/success", process.env.APP_URL)
);
}