Feature/wrap logging * feat: change all logging to go through our own logger function so that we can control log levels * move packages/trpc to using our own logger * merge Approved-by: Linus Flood
110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
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)
|