Merged in feat/LOY-230-Microsoft-Entra-ID-Auth (pull request #2113)

Feat(LOY-230): DTMC Routes with Entra ID Auth & Error Page Handling

* feat(LOY-230): Link Scandic Friends and Azure accounts

* fix(LOY-230): remove employee id param setting

* fix(LOY-230): return token in jwt callback for auth.dtmc.ts


Approved-by: Michael Zetterberg
Approved-by: Christian Andolf
This commit is contained in:
Chuma Mcphoy (We Ahead)
2025-06-18 10:22:04 +00:00
parent 9df19fda7c
commit 2101b79db1
23 changed files with 568 additions and 165 deletions

View File

@@ -0,0 +1,105 @@
import NextAuth, { type NextAuthConfig } from "next-auth"
import MicrosoftEntraID from "next-auth/providers/microsoft-entra-id"
import { env } from "@/env/server"
const config = {
basePath: "/api/web/auth",
debug: env.NEXTAUTH_DEBUG,
cookies: {
sessionToken: {
name: "dtmc.session-token",
},
},
providers: [
MicrosoftEntraID({
clientId: env.DTMC_ENTRA_ID_CLIENT,
clientSecret: env.DTMC_ENTRA_ID_SECRET,
issuer: env.DTMC_ENTRA_ID_ISSUER,
authorization: {
params: {
scope: "openid profile email User.Read",
},
},
}),
],
redirectProxyUrl: env.NEXTAUTH_REDIRECT_PROXY_URL,
trustHost: true,
session: {
strategy: "jwt",
maxAge: 10 * 60, // 10 minutes
},
callbacks: {
async signIn() {
return true
},
async session({ session, token }) {
if (token && token.employeeId && typeof token.employeeId === "string") {
session.employeeId = token.employeeId
}
return session
},
async redirect({ baseUrl, url }) {
console.log(`[auth.dtmc] deciding redirect URL`, { baseUrl, url })
if (url.startsWith("/")) {
console.log(
`[auth.dtmc] relative URL accepted, returning: ${baseUrl}${url}`
)
// Allows relative callback URLs
return `${baseUrl}${url}`
} else {
// Assume absolute URL
try {
const parsedUrl = new URL(url)
if (
/\.scandichotels\.(dk|de|com|fi|no|se)$/.test(parsedUrl.hostname)
) {
console.log(`[auth.dtmc] subdomain URL accepted, returning: ${url}`)
// Allows any subdomains on all top level domains above
return url
} else if (parsedUrl.origin === baseUrl) {
// Allows callback URLs on the same origin
console.log(`[auth.dtmc] origin URL accepted, returning: ${url}`)
return url
}
} catch (e) {
console.error(
`[auth.dtmc] error parsing incoming URL for redirection`,
e
)
}
}
console.log(`[auth.dtmc] URL denied, returning base URL: ${baseUrl}`)
return baseUrl
},
async authorized() {
return true
},
async jwt({ account, trigger, profile, token }) {
if (
trigger === "signIn" &&
account &&
account.provider === "microsoft-entra-id" &&
profile
) {
const employeeId = profile["user.employeeid"]
if (employeeId && typeof employeeId === "string") {
return {
access_token: "", // JWT requires it, but DTMC does not need it, so save on cookie size by using empty string
loginType: "dtmc",
employeeId,
}
}
}
return token
},
},
} satisfies NextAuthConfig
export const {
auth,
handlers: { GET, POST },
signIn,
signOut,
} = NextAuth(config)