ultisuite-client/app/api/auth/login/route.ts
2026-05-25 13:52:40 +02:00

78 lines
2.3 KiB
TypeScript

import { cookies } from "next/headers"
import { NextResponse } from "next/server"
import { createPkcePair, randomString } from "@/lib/auth/pkce"
import { platformUserFromToken } from "@/lib/auth/jwt-claims"
import { resolveOidcConfig, getAppOrigin } from "@/lib/auth/oidc-config"
const PKCE_COOKIE = "ulti_pkce_verifier"
const STATE_COOKIE = "ulti_oauth_state"
const INTENT_COOKIE = "ulti_auth_intent"
const PREVIOUS_SUB_COOKIE = "ulti_auth_previous_sub"
const COOKIE_MAX_AGE = 600
function oauthCookieOptions() {
return {
httpOnly: true,
sameSite: "lax" as const,
path: "/",
maxAge: COOKIE_MAX_AGE,
secure: process.env.NODE_ENV === "production",
}
}
export async function GET(request: Request) {
let cfg
try {
cfg = await resolveOidcConfig()
} catch (err) {
const message =
err instanceof Error ? err.message : "oidc_discovery_failed"
return NextResponse.redirect(
new URL(
`/login?error=${encodeURIComponent(message)}`,
getAppOrigin()
)
)
}
const { verifier, challenge } = await createPkcePair()
const state = randomString(16)
const requestUrl = new URL(request.url)
const returnTo = requestUrl.searchParams.get("returnTo") ?? "/mail/inbox"
const intent = requestUrl.searchParams.get("intent")
const prompt =
requestUrl.searchParams.get("prompt") ??
(intent === "add_account" ? "login select_account" : "select_account")
const jar = await cookies()
const existingUser = platformUserFromToken(
jar.get("ulti_access_token")?.value ?? ""
)
const params = new URLSearchParams({
client_id: cfg.clientId,
redirect_uri: cfg.redirectUri,
response_type: "code",
scope: "openid profile email offline_access",
state,
code_challenge: challenge,
code_challenge_method: "S256",
prompt,
})
const response = NextResponse.redirect(
`${cfg.authorizationEndpoint}?${params.toString()}`
)
const cookieOpts = oauthCookieOptions()
response.cookies.set(PKCE_COOKIE, verifier, cookieOpts)
response.cookies.set(STATE_COOKIE, state, cookieOpts)
response.cookies.set("ulti_auth_return", returnTo, cookieOpts)
if (intent === "add_account") {
response.cookies.set(INTENT_COOKIE, "add_account", cookieOpts)
if (existingUser?.sub) {
response.cookies.set(PREVIOUS_SUB_COOKIE, existingUser.sub, cookieOpts)
}
}
return response
}