import { NextResponse, type NextRequest } from "next/server"; import { AUTH_VALIDATE_URL, DEFAULT_COOKIE_NAMES } from "./constants"; import type { SfAuthCookieNames } from "./middleware"; export type SfAuthCallbackOptions = { redirectTo: string; cookieNames?: SfAuthCookieNames; validateEndpoint?: string; }; type ValidateResponse = { valid: boolean; user_id: string; }; const resolveCookieNames = (cookieNames?: SfAuthCookieNames) => ({ userId: cookieNames?.userId ?? DEFAULT_COOKIE_NAMES.userId, username: cookieNames?.username ?? DEFAULT_COOKIE_NAMES.username }); const errorResponse = (message: string, status = 400) => new NextResponse(message, { status, headers: { "content-type": "text/plain; charset=utf-8" } }); export const createSfAuthCallbackRoute = ( options: SfAuthCallbackOptions ) => { const cookieNames = resolveCookieNames(options.cookieNames); const validateUrl = options.validateEndpoint ?? AUTH_VALIDATE_URL; return async (request: NextRequest) => { const url = new URL(request.url); const userId = url.searchParams.get("user_id"); const username = url.searchParams.get("username"); const key = url.searchParams.get("key"); if (!userId || !username || !key) { return errorResponse("Missing required query parameters."); } let validateResponse: ValidateResponse; try { const response = await fetch(validateUrl, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ user_id: userId, key }) }); if (!response.ok) { return errorResponse("Failed to validate credentials."); } validateResponse = (await response.json()) as ValidateResponse; } catch (error) { return errorResponse("Unable to validate credentials.", 500); } if (!validateResponse.valid || validateResponse.user_id !== userId) { return errorResponse("Invalid credentials."); } const redirectTarget = new URL(options.redirectTo, request.url); const response = NextResponse.redirect(redirectTarget); response.cookies.set(cookieNames.userId, userId, { httpOnly: true, sameSite: "lax", path: "/" }); response.cookies.set(cookieNames.username, username, { httpOnly: true, sameSite: "lax", path: "/" }); return response; }; };