import { type NextRequest, NextResponse } from "next/server" import { AuthError } from "next-auth" import { logger } from "@scandic-hotels/common/logger" import { badRequest, internalServerError } from "@/server/errors/next" import { getPublicURL } from "@/server/utils" import { signIn } from "@/auth" import type { Lang } from "@scandic-hotels/common/constants/language" export async function GET( request: NextRequest, context: { params: Promise<{ lang: Lang }> } ) { const publicURL = getPublicURL(request) const loginKey = request.nextUrl.searchParams.get("loginKey") if (!loginKey) { logger.debug( `[verifymagiclink] missing required loginKey, aborting bad request` ) return badRequest() } let redirectTo: string logger.debug(`[verifymagiclink] verifying callback`) const redirectToCookieValue = request.cookies.get( "magicLinkRedirectTo" )?.value // Set redirect url from the magicLinkRedirect Cookie which is set when intiating login const redirectToFallback = "/" logger.debug( `[verifymagiclink] magicLinkRedirectTo cookie value: ${redirectToCookieValue}` ) redirectTo = redirectToCookieValue || redirectToFallback // Make relative URL to absolute URL if (redirectTo.startsWith("/")) { logger.debug( `[verifymagiclink] make redirectTo absolute, from ${redirectTo}` ) redirectTo = new URL(redirectTo, publicURL).href logger.debug(`[verifymagiclink] make redirectTo absolute, to ${redirectTo}`) } // Update Seamless login url as Magic link login has a different authenticator in Curity redirectTo = redirectTo.replace("updatelogin", "updateloginemail") // https://scandichotels.atlassian.net/browse/SW-2506 // Encode the returnUrl which is passed as search parameter to the old web. // Use of substring because creating URL object and using searchParams causes partial param retrival const returnUrl = redirectTo.substring(redirectTo.indexOf("returnurl=") + 10) redirectTo = redirectTo.replace( /returnurl.*/gi, "returnurl=" + encodeURIComponent(returnUrl) ) try { logger.debug(`[verifymagiclink] final redirectUrl: ${redirectTo}`) const params = await context.params /** * 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, }, { ui_locales: params.lang, scope: [ "openid", "profile", "booking", "availability", "profile_link", "profile_matchtier", "profile_point_transfer", ].join(" "), loginKey: loginKey, for_origin: publicURL, acr_values: "urn:com:scandichotels:scandic-email", version: "2", } ) if (redirectUrl) { logger.debug(`[verifymagiclink] redirecting to: ${redirectUrl}`) return NextResponse.redirect(redirectUrl) } else { logger.error( `[verifymagiclink] missing redirectUrl reponse from signIn()` ) } } catch (error) { if (error instanceof AuthError) { logger.error("signInAuthError", { signInAuthError: error }) } else { logger.error("signInError", { signInError: error }) } } return internalServerError() }