From 13ded529ccbc599c03fad0f87cc4e5d68054fe34 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Fri, 9 Aug 2024 13:18:49 +0200 Subject: [PATCH] feat(SW-162): Updated MFA to use basic cookie validation --- app/[lang]/(live)/(public)/login/route.ts | 2 +- auth.ts | 21 ++++++------- middlewares/authRequired.ts | 36 ++++++----------------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/app/[lang]/(live)/(public)/login/route.ts b/app/[lang]/(live)/(public)/login/route.ts index 9f1a682e7..69884a944 100644 --- a/app/[lang]/(live)/(public)/login/route.ts +++ b/app/[lang]/(live)/(public)/login/route.ts @@ -15,7 +15,7 @@ export async function GET( let redirectTo: string const returnUrl = request.headers.get("x-returnurl") - const isMFA = request.headers.get("mfa-login") + const isMFA = request.headers.get("x-mfa-login") if (returnUrl) { // Seamless login request from Current web diff --git a/auth.ts b/auth.ts index 33b093d4e..5cb359970 100644 --- a/auth.ts +++ b/auth.ts @@ -143,18 +143,15 @@ export const config = { async jwt({ account, session, token, trigger, user }) { if (account?.provider == "curity-mfa") { const cookieStore = cookies() - const value = token.access_token - const secret = env.NEXTAUTH_SECRET - const maxAge = 60 * 15 - const name = "_SecureMFA-token" - const mfaCookie = await encode({ - secret, - maxAge, - token: value, - salt: name, - }) - cookieStore.set("_SecureMFA-token", mfaCookie.toString(), { - maxAge: maxAge, + // As new scope/token is added to existing session we will add separate cookie to validate MFA done + cookieStore.set({ + name: "_MFA-validated-cookie", + value: "true", + httpOnly: true, + sameSite: "lax", + expires: token.expires_at + ? token.expires_at * 1000 + : Date.now() + 10 * 60 * 1000, }) } diff --git a/middlewares/authRequired.ts b/middlewares/authRequired.ts index a6b2d4147..aa44e910a 100644 --- a/middlewares/authRequired.ts +++ b/middlewares/authRequired.ts @@ -1,4 +1,3 @@ -import { decode } from "@auth/core/jwt" import { cookies } from "next/headers" import { NextResponse } from "next/server" @@ -55,36 +54,19 @@ export const middleware = auth(async (request) => { nextUrlClone.host = publicUrl.host nextUrlClone.hostname = publicUrl.hostname - async function isMFAInvalid() { + /** + * Function to validate MFA cookie expiry + * @returns boolean + */ + function isMFAInvalid() { + const isMFAPath = mfaRequired.includes(nextUrl.pathname) const cookieStore = cookies() - const mfaCookieValue = cookieStore.get("_SecureMFA-token")?.value - if (mfaCookieValue) { - try { - const mfaToken = await decode({ - token: mfaCookieValue, - secret: env.NEXTAUTH_SECRET, - salt: "_SecureMFA-token", - }) - if (mfaToken?.exp) { - return false - } else { - return true - } - } catch (e) { - console.log("JWT decode failed", e) - cookieStore.set("_SecureMFA-token", "", { maxAge: 0 }) - return true - } - } else { - return true - } + return isMFAPath && !cookieStore.get("_MFA-validated-cookie")?.value } - const isMFAPath = mfaRequired.includes(nextUrl.pathname) - const mfaInvalid = isMFAPath ? await isMFAInvalid() : false - if (isLoggedIn && mfaInvalid) { + if (isLoggedIn && isMFAInvalid()) { const headers = new Headers(request.headers) - headers.set("mfa-login", "true") + headers.set("x-mfa-login", "true") headers.set("x-returnurl", request.nextUrl.href) return NextResponse.rewrite(new URL(`/${lang}/login`, request.nextUrl), { request: {