Reubencf's picture
Deploy PraxaLing: component refactor, bug fixes, unified neo-brutal design, Qwen3.5 everywhere
2992997
Raw
History Blame Contribute Delete
2.47 kB
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import { hfExchangeCode, hfFetchUser, hfOriginFromRequest } from "@/lib/auth/hf";
import { signSession, setSessionCookie } from "@/lib/auth/session";
const OAUTH_STATE_COOKIES = ["hf_oauth_state", "hf_oauth_verifier", "hf_oauth_client"] as const;
function clearOAuthStateCookies(res: NextResponse) {
const isProd = process.env.NODE_ENV === "production";
const opts = {
httpOnly: true,
secure: isProd,
sameSite: (isProd ? "none" : "lax") as "none" | "lax",
path: "/",
maxAge: 0,
};
for (const name of OAUTH_STATE_COOKIES) {
res.cookies.set(name, "", opts);
}
}
export async function GET(req: Request) {
const url = new URL(req.url);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const clientFlag = url.searchParams.get("client");
const cookieJar = await cookies();
const storedState = cookieJar.get("hf_oauth_state")?.value;
const verifier = cookieJar.get("hf_oauth_verifier")?.value;
const clientKind = clientFlag === "mobile" ? "mobile" : cookieJar.get("hf_oauth_client")?.value ?? "web";
if (!code || !state || !verifier || state !== storedState) {
const res = NextResponse.json({ error: "invalid_state" }, { status: 400 });
clearOAuthStateCookies(res);
return res;
}
const origin = hfOriginFromRequest(req);
const redirectUri =
clientKind === "mobile"
? `${origin}/api/auth/callback/huggingface?client=mobile`
: `${origin}/api/auth/callback/huggingface`;
let tokens;
try {
tokens = await hfExchangeCode(redirectUri, code, verifier);
} catch (err) {
console.error("hf token exchange failed", err);
const res = NextResponse.json({ error: "token_exchange_failed" }, { status: 400 });
clearOAuthStateCookies(res);
return res;
}
const accessToken = tokens.accessToken();
const hfUser = await hfFetchUser(accessToken);
const jwt = await signSession({
hfId: hfUser.sub,
hfUsername: hfUser.preferred_username,
email: hfUser.email,
avatarUrl: hfUser.picture,
accessToken,
});
if (clientKind === "mobile") {
const res = NextResponse.redirect(`langlearn://auth/callback?token=${encodeURIComponent(jwt)}`);
clearOAuthStateCookies(res);
return res;
}
const res = NextResponse.redirect(`${origin}/practice`);
setSessionCookie(res, jwt);
clearOAuthStateCookies(res);
return res;
}