import NextAuth, { type NextAuthConfig } from "next-auth" import MicrosoftEntraID from "next-auth/providers/microsoft-entra-id" import { logger } from "@scandic-hotels/common/logger" 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 }) { logger.debug(`[auth.dtmc] deciding redirect URL`, { baseUrl, url }) if (url.startsWith("/")) { logger.debug( `[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) ) { logger.debug( `[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 logger.debug(`[auth.dtmc] origin URL accepted, returning: ${url}`) return url } } catch (e) { logger.error( `[auth.dtmc] error parsing incoming URL for redirection`, e ) } } logger.debug(`[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)