From e36f5cd1221b7ce984d27456ac24458d21f658ee Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Mon, 8 Jul 2024 11:39:36 +0200 Subject: [PATCH] feat: SW-158 Adding route and support for Magic link --- app/[lang]/(live)/(public)/login/route.ts | 5 ++ .../(live)/(public)/verifymagiclink/route.ts | 75 +++++++++++++++++++ constants/routes/handleAuth.js | 16 +++- 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 app/[lang]/(live)/(public)/verifymagiclink/route.ts diff --git a/app/[lang]/(live)/(public)/login/route.ts b/app/[lang]/(live)/(public)/login/route.ts index 5ccb67d44..ee8014743 100644 --- a/app/[lang]/(live)/(public)/login/route.ts +++ b/app/[lang]/(live)/(public)/login/route.ts @@ -106,6 +106,11 @@ export async function GET( * to the user which we do not want. */ acr_values: "acr", + /** + * The `for_origin` param is used to make Curity email login functionality working. + * Without the parameter Curity gives Internal Error issue for login with Email link. + */ + for_origin: env.PUBLIC_URL, } const redirectUrl = await signIn( "curity", diff --git a/app/[lang]/(live)/(public)/verifymagiclink/route.ts b/app/[lang]/(live)/(public)/verifymagiclink/route.ts new file mode 100644 index 000000000..705f8e166 --- /dev/null +++ b/app/[lang]/(live)/(public)/verifymagiclink/route.ts @@ -0,0 +1,75 @@ +import { 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 { signIn } from "@/auth" + +export async function GET( + request: NextRequest, + context: { params: { lang: Lang } } +) { + let redirectHeaders: Headers | undefined = undefined + let redirectTo: string + let nonce: string + let value: string + + redirectTo = + request.cookies.get("redirectTo")?.value || // Cookie gets set by authRequired middleware + request.nextUrl.searchParams.get("redirectTo") || + "/" + + // Make relative URL to absolute URL + if (redirectTo.startsWith("/")) { + if (!env.PUBLIC_URL) { + throw internalServerError("No value for env.PUBLIC_URL") + } + redirectTo = new URL(redirectTo, env.PUBLIC_URL).href + } + + // 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" + ) + nonce = "" + request.nextUrl.searchParams.get("nonce")?.toString() + value = "" + request.nextUrl.searchParams.get("nonce")?.toString() + + try { + /** + * 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 + */ + console.log({ login_redirectTo: redirectTo }) + let redirectUrl = await signIn( + "curity", + { + redirectTo, + redirect: false, + }, + [ + ["ui_locales", context.params.lang], + ["nonce", nonce], + ["acr_values", "cat"], + ] + ) + + if (redirectUrl) { + return NextResponse.redirect(redirectUrl, { + headers: redirectHeaders, + }) + } + } catch (error) { + if (error instanceof AuthError) { + console.error({ signInAuthError: error }) + } else { + console.error({ signInError: error }) + } + } + + return internalServerError() +} diff --git a/constants/routes/handleAuth.js b/constants/routes/handleAuth.js index 042ffba6d..a695dfa6d 100644 --- a/constants/routes/handleAuth.js +++ b/constants/routes/handleAuth.js @@ -22,4 +22,18 @@ export const logout = { sv: "/sv/logga-ut", } -export const handleAuth = [...Object.values(login), ...Object.values(logout)] +/** @type {import('@/types/routes').LangRoute} */ +export const verifymagiclink = { + da: "/da/verifymagiclink", + de: "/de/verifymagiclink", + en: "/en/verifymagiclink", + fi: "/fi/verifymagiclink", + no: "/no/verifymagiclink", + sv: "/sv/verifymagiclink", +} + +export const handleAuth = [ + ...Object.values(login), + ...Object.values(logout), + ...Object.values(verifymagiclink), +]