feat: SW-162 Updated as per review comments

This commit is contained in:
Hrishikesh Vaipurkar
2024-07-17 16:12:18 +02:00
parent 77feefb1dd
commit 8ab77a5522
5 changed files with 59 additions and 38 deletions

View File

@@ -41,18 +41,13 @@ export async function GET(
* https://github.com/nextauthjs/next-auth/blob/3c035ec/packages/next-auth/src/lib/actions.ts#L76
*/
const redirectUrl = await signIn(
"curity",
"curity-mfa",
{
redirectTo,
redirect: false,
},
{
ui_locales: context.params.lang,
scope: "profile_update openid profile",
// 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 ID and secret
acr_values:
"urn:se:curity:authentication:otp-authenticator:OTP-Authenticator_web",
}
)

70
auth.ts
View File

@@ -1,4 +1,4 @@
import { decode,encode } from "@auth/core/jwt"
import { encode } from "@auth/core/jwt"
import { cookies } from "next/headers"
import NextAuth from "next-auth"
@@ -22,18 +22,39 @@ function getLoginType(user: User) {
}
}
const customProvider = {
const sharedConfig = {
clientId: env.CURITY_CLIENT_ID_USER,
clientSecret: env.CURITY_CLIENT_SECRET_USER,
id: "curity",
name: "Curity",
type: "oidc",
// FIXME: This is incorrect. We should not hard code this.
// It should be ${env.CURITY_ISSUER_USER}.
// This change requires sync between Curity deploy and CurrentWeb and NewWeb.
issuer: "https://scandichotels.com",
authorization: {
url: `${env.CURITY_ISSUER_USER}/oauth/v2/authorize`,
},
token: {
url: `${env.CURITY_ISSUER_USER}/oauth/v2/token`,
},
userinfo: {
url: `${env.CURITY_ISSUER_USER}/oauth/v2/userinfo`,
},
profile(profile: User) {
return {
id: profile.id,
sub: profile.sub,
given_name: profile.given_name,
login_with: profile.login_with,
}
},
}
const curityProvider = {
...sharedConfig,
id: "curity",
name: "Curity",
type: "oidc",
authorization: {
...sharedConfig.authorization,
params: {
scope: ["openid", "profile"].join(" "),
/**
@@ -44,27 +65,30 @@ const customProvider = {
acr_values: "acr",
},
},
token: {
url: `${env.CURITY_ISSUER_USER}/oauth/v2/token`,
},
userinfo: {
url: `${env.CURITY_ISSUER_USER}/oauth/v2/userinfo`,
},
} satisfies OIDCConfig<User>
profile(profile) {
return {
id: profile.id,
sub: profile.sub,
given_name: profile.given_name,
login_with: profile.login_with,
acr: profile.acr,
}
const curityMFAProvider = {
...sharedConfig,
id: "curity-mfa",
name: "Curity MFA",
type: "oidc",
authorization: {
...sharedConfig.authorization,
params: {
scope: ["profile_update", "openid"].join(" "),
/**
* 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 ID and secret
*/
acr_values:
"urn:se:curity:authentication:otp-authenticator:OTP-Authenticator_web",
},
},
} satisfies OIDCConfig<User>
export const config = {
debug: env.NEXTAUTH_DEBUG,
providers: [customProvider],
providers: [curityProvider, curityMFAProvider],
redirectProxyUrl: env.NEXTAUTH_REDIRECT_PROXY_URL,
trustHost: true,
session: {
@@ -117,10 +141,7 @@ export const config = {
return true
},
async jwt({ account, session, token, trigger, user }) {
if (
user?.acr ==
"urn:se:curity:authentication:otp-authenticator:OTP-Authenticator_web"
) {
if (account?.provider == "curity-mfa") {
const cookieStore = cookies()
const value = token.access_token
const secret = env.NEXTAUTH_SECRET
@@ -135,6 +156,7 @@ export const config = {
cookieStore.set("_SecureMFA-token", mfaCookie.toString(), {
maxAge: maxAge,
})
return null
}
const loginType = getLoginType(user)

View File

@@ -55,7 +55,7 @@ export const middleware = auth(async (request) => {
nextUrlClone.host = publicUrl.host
nextUrlClone.hostname = publicUrl.hostname
const isMFAValid = async function () {
async function isMFAInvalid() {
const cookieStore = cookies()
const mfaCookieValue = cookieStore.get("_SecureMFA-token")?.value
if (mfaCookieValue) {
@@ -66,22 +66,22 @@ export const middleware = auth(async (request) => {
salt: "_SecureMFA-token",
})
if (mfaToken?.exp) {
return true
return false
}
} catch (e) {
console.log("JWT decode failed", e)
cookieStore.set("_SecureMFA-token", "", { maxAge: 0 })
return false
return true
}
} else {
return false
return true
}
}
if (isLoggedIn && !hasError) {
const isMFAPath = mfaRequired.includes(nextUrl.pathname)
const mfaValid = isMFAPath ? await isMFAValid() : true
if (!mfaValid) {
const mfaInvalid = isMFAPath ? await isMFAInvalid() : false
if (mfaInvalid) {
const mfaLoginUrl = mfaLogin[lang]
const nextUrlClone = nextUrl.clone()
nextUrlClone.host = publicUrl.host

View File

@@ -1,7 +1,7 @@
import createJiti from "jiti"
import { fileURLToPath } from "url"
import { login, logout } from "./constants/routes/handleAuth.js"
import { login, logout, mfaLogin } from "./constants/routes/handleAuth.js"
import { hotelReservation } from "./constants/routes/hotelReservation.js"
import { myPages } from "./constants/routes/myPages.js"
@@ -80,6 +80,11 @@ const nextConfig = {
{ source: logout.fi, destination: "/fi/logout" },
{ source: logout.no, destination: "/no/logout" },
{ source: logout.sv, destination: "/sv/logout" },
{ source: mfaLogin.da, destination: "/da/mfa-login" },
{ source: mfaLogin.de, destination: "/de/mfa-login" },
{ source: mfaLogin.fi, destination: "/fi/mfa-login" },
{ source: mfaLogin.no, destination: "/no/mfa-login" },
{ source: mfaLogin.sv, destination: "/sv/mfa-login" },
{
source: `${myPages.en}/:path*`,
destination: `/en/my-pages/:path*`,

1
types/auth.d.ts vendored
View File

@@ -27,6 +27,5 @@ declare module "next-auth" {
sub: string
email?: string
login_with: string
acr?: string
}
}