31 lines
1.5 KiB
TypeScript
31 lines
1.5 KiB
TypeScript
/**
|
||
* 第三方登录的服务端跳转入口。只接受固定provider及单一PKCE challenge,
|
||
* 重定向到配置的Foundry项目,不交换令牌、不读取verifier,也不在此创建会话Cookie。
|
||
*/
|
||
import { NextRequest, NextResponse } from "next/server";
|
||
|
||
/** await异步provider参数,challenge须为43字符base64url;多值或未知provider直接400。
|
||
* 302显式no-store,避免浏览器把某一次登录challenge的跳转当成可复用响应。 */
|
||
export async function GET(
|
||
req: NextRequest,
|
||
{ params }: { params: Promise<{ provider: string }> },
|
||
) {
|
||
const { provider } = await params;
|
||
const challenges = req.nextUrl.searchParams.getAll("challenge");
|
||
// 这里只验证 challenge 字符表示,不验证 verifier/登录 state 或交换身份;额外查询参数也不会透传上游。
|
||
const challenge = challenges[0];
|
||
if (
|
||
!["google", "slack"].includes(provider) ||
|
||
challenges.length !== 1 ||
|
||
!/^[-_a-zA-Z0-9]{43}$/.test(challenge)
|
||
)
|
||
return NextResponse.json({ error: "invalid_request" }, { status: 400 });
|
||
// 上游源站/项目由宿主环境装配,不让查询参数决定任意OAuth重定向目标。
|
||
const origin = process.env.FOUNDRY_API_ORIGIN || "https://api.foundry.entroia.com";
|
||
const project = process.env.NEXT_PUBLIC_FOUNDRY_PROJECT || "endoleap";
|
||
return NextResponse.redirect(
|
||
origin + "/projects/" + encodeURIComponent(project) + "/auth/" + provider + "?challenge=" + challenge,
|
||
{ status: 302, headers: { "Cache-Control": "no-store" } },
|
||
);
|
||
}
|