import crypto from "crypto" import { NextResponse } from "next/server" import { getSessionUser } from "@/lib/session" import { getAccountContext } from "@/lib/account" import { getProvider } from "@/lib/accounting" import { signState, OAUTH_NONCE_COOKIE } from "@/lib/accounting/state" // Starts the OAuth connect flow for an accounting provider (owner-only). export async function GET(request: Request, { params }: { params: Promise<{ provider: string }> }) { const { provider: pid } = await params const prov = getProvider(pid) const settings = new URL("/settings/integrations", request.url) if (!prov) { settings.searchParams.set("error", "unknown_provider") return NextResponse.redirect(settings) } const user = await getSessionUser() if (!user) return NextResponse.redirect(new URL("/login", request.url)) const ctx = await getAccountContext(user.id) if (!ctx.isOwner) { settings.searchParams.set("error", "owner_only") return NextResponse.redirect(settings) } if (!prov.configured()) { settings.searchParams.set("error", "not_configured") return NextResponse.redirect(settings) } // Bind the OAuth round-trip to this browser: a random nonce goes into the // signed state AND an httpOnly cookie; the callback requires them to match. const nonce = crypto.randomUUID() const state = signState({ ownerId: ctx.ownerId, provider: pid, nonce }) const res = NextResponse.redirect(prov.getAuthUrl(state)) res.cookies.set(OAUTH_NONCE_COOKIE, nonce, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", path: "/", maxAge: 600, }) return res }