import { type NextRequest, NextResponse } from "next/server" import { AuthError } from "next-auth" import { Lang } from "@/constants/languages" import { env } from "@/env/server" import { internalServerError } from "@/server/errors/next" import { getPublicURL } from "@/server/utils" import { signIn } from "@/auth" export async function GET( request: NextRequest, context: { params: { lang: Lang } } ) { const publicURL = getPublicURL(request) let redirectHeaders: Headers | undefined = undefined let redirectTo: string const returnUrl = request.headers.get("x-returnurl") const isSeamless = request.headers.get("x-login-source") === "seamless" const isMFA = request.headers.get("x-login-source") === "mfa" const isSeamlessMagicLink = request.headers.get("x-login-source") === "seamless-magiclink" console.log( `[login] source: ${request.headers.get("x-login-source") || "normal"}` ) const redirectToCookieValue = request.cookies.get("redirectTo")?.value // Cookie gets set by authRequired middleware const redirectToSearchParamValue = request.nextUrl.searchParams.get("redirectTo") const redirectToFallback = "/" console.log(`[login] redirectTo cookie value: ${redirectToCookieValue}`) console.log( `[login] redirectTo search param value: ${redirectToSearchParamValue}` ) if (isSeamless || isSeamlessMagicLink || isMFA) { if (returnUrl) { redirectTo = returnUrl } else { console.log( `[login] missing returnUrl, using fallback: ${redirectToFallback}` ) redirectTo = redirectToFallback } } else { redirectTo = redirectToCookieValue || redirectToSearchParamValue || redirectToFallback // Make relative URL to absolute URL if (redirectTo.startsWith("/")) { console.log(`[login] make redirectTo absolute, from ${redirectTo}`) redirectTo = new URL(redirectTo, publicURL).href console.log(`[login] make redirectTo absolute, to ${redirectTo}`) } // Clean up cookie from authRequired middleware redirectHeaders = new Headers() redirectHeaders.append( "set-cookie", "redirectTo=; Expires=Thu, 01 Jan 1970 00:00:00 UTC; Path=/; HttpOnly; SameSite=Lax" ) try { // Initiate the seamless login flow let redirectUrlValue switch (context.params.lang) { case Lang.da: redirectUrlValue = env.SEAMLESS_LOGIN_DA break case Lang.de: redirectUrlValue = env.SEAMLESS_LOGIN_DE break case Lang.en: redirectUrlValue = env.SEAMLESS_LOGIN_EN break case Lang.fi: redirectUrlValue = env.SEAMLESS_LOGIN_FI break case Lang.no: redirectUrlValue = env.SEAMLESS_LOGIN_NO break case Lang.sv: redirectUrlValue = env.SEAMLESS_LOGIN_SV break } const redirectUrl = new URL(redirectUrlValue) console.log(`[login] creating redirect to seamless login: ${redirectUrl}`) redirectUrl.searchParams.set("returnurl", redirectTo) console.log( `[login] returnurl for seamless login: ${redirectUrl.searchParams.get("returnurl")}` ) redirectTo = redirectUrl.toString() /** Set cookie with redirect Url to appropriately redirect user when using magic link login */ redirectHeaders.append( "set-cookie", "magicLinkRedirectTo=" + redirectTo + "; Max-Age=300; Path=/; HttpOnly; SameSite=Lax" ) } catch (e) { console.error( "[login] unable to create URL for seamless login, proceeding without it.", e ) } } try { console.log(`[login] final redirectUrl: ${redirectTo}`) console.log({ login_env: process.env }) /** Record is next-auth typings */ const params: Record = { ui_locales: context.params.lang, scope: ["openid", "profile", "booking", "profile_link"], /** * The `acr_values` param is used to make Curity display the proper login * page for Scandic. Without the parameter Curity presents some choices * to the user which we do not want. */ acr_values: "urn:com:scandichotels:scandic", /** * Both of the below two params are required to send for initiating login as well * because user might choose to do Email link login. * */ // The `for_origin` param is used to make Curity email login functionality working. for_origin: publicURL, // This is new param set for differentiate between the Magic link login of New web and current web version: "2", } if (isMFA) { // Append profile_update scope for MFA params.scope.push("profile_update") /** * The below acr value is required as for New Web same Curity Client is used for MFA * while in current web it is being setup using different Curity Client */ params.acr_values = "urn:com:scandichotels:scandic-otp" } else if (isSeamlessMagicLink) { params.acr_values = "urn:com:scandichotels:scandic-email" } params.scope = params.scope.join(" ") /** * Passing `redirect: false` to `signIn` will return the URL instead of * automatically redirecting to it inside of `signIn`. * https://github.com/nextauthjs/next-auth/blob/3c035ec/packages/next-auth/src/lib/actions.ts#L76 */ const redirectUrl = await signIn( "curity", { redirectTo, redirect: false, }, params ) if (redirectUrl) { const redirectOpts = { headers: redirectHeaders, } console.log(`[login] redirecting to: ${redirectUrl}`, redirectOpts) return NextResponse.redirect(redirectUrl, redirectOpts) } else { console.error(`[login] missing redirectUrl reponse from signIn()`) } } catch (error) { if (error instanceof AuthError) { console.error({ signInAuthError: error }) } else { console.error({ signInError: error }) } } return internalServerError() }