Engineering manualAPI route source
/api/auth/google/exchange
Exact current route handler: hosted-app/app/api/auth/google/exchange/route.js
Methods: POST. Input signals: JSON body, query parameters. Literal response-status signals: 400, 401, 503.
Source: hosted-app/app/api/auth/google/exchange/route.js. Imports: ../../../../../lib/supabase-rest.mjs, next/server. Exact source is shown for inspection; its presence does not prove authentication, validation or live behavior.
All API routes · API and execution contract
import { NextResponse } from "next/server";
import { supabaseConfigFromEnv } from "../../../../../lib/supabase-rest.mjs";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
const PKCE_COOKIE = "brand-studio.oauth_pkce";
const validAuthCode = (value) => /^[0-9a-f-]{36}$/i.test(String(value || ""));
const clearVerifier = (response, request) => {
response.headers.set("cache-control", "no-store");
response.cookies.set(PKCE_COOKIE, "", {
httpOnly: true,
secure: new URL(request.url).protocol === "https:",
sameSite: "lax",
path: "/api/auth/google/exchange",
maxAge: 0
});
return response;
};
export async function POST(request) {
const { supabaseUrl, supabaseAnonKey } = supabaseConfigFromEnv(process.env);
if (!supabaseUrl || !supabaseAnonKey) {
return NextResponse.json({ status: "refused", reason: "supabase_not_configured" }, { status: 503 });
}
const verifier = request.cookies.get(PKCE_COOKIE)?.value || "";
const body = await request.json().catch(() => ({}));
const authCode = String(body.auth_code || "");
if (!verifier || !validAuthCode(authCode)) {
return clearVerifier(
NextResponse.json({ status: "refused", reason: "invalid_or_unsolicited_oauth_callback" }, { status: 400 }),
request
);
}
const exchanged = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=pkce`, {
method: "POST",
headers: { apikey: supabaseAnonKey, "content-type": "application/json" },
body: JSON.stringify({ auth_code: authCode, code_verifier: verifier })
});
const payload = await exchanged.json().catch(() => ({}));
if (!exchanged.ok || !payload?.access_token) {
return clearVerifier(
NextResponse.json({ status: "refused", reason: "oauth_code_exchange_failed" }, { status: 401 }),
request
);
}
return clearVerifier(NextResponse.json({
status: "passed",
access_token: payload.access_token,
refresh_token: payload.refresh_token ?? null,
expires_at: payload.expires_at ?? null,
user: { id: payload.user?.id || null, email: payload.user?.email || null }
}), request);
}