Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Added SessionGuard component to manage session expiration and online status. - Updated AuthProvider to streamline session fetching and handling. - Introduced IdentityProvidersSection for managing OAuth, SAML, and LDAP identity providers. - Implemented identity provider guides for easier configuration. - Enhanced mail settings with infinite scroll option for improved user experience. - Updated global styles and layout components for better consistency across the application.
76 lines
2.3 KiB
TypeScript
76 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"
|
|
import { sessionCookieOptions } from "@/lib/auth/session"
|
|
|
|
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 {
|
|
...sessionCookieOptions(),
|
|
maxAge: COOKIE_MAX_AGE,
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|