跨子域Next.js应用用auth.js认证遇UntrustedHost问题求助
跨子域Next.js应用的Auth.js认证问题解决指南
问题背景
在Next.js多区域架构中使用Auth.js时,https://console.my-app.com下的多个应用均重写到部署了自定义认证中间件的主应用;另有独立部署在https://panel.my-app.com的应用,不做重写。原本通过同一Auth.js配置实现了跨子域共享登录、认证有效,但现在panel.my-app.com认证失效,服务器报错:
panel:start: [auth][error] UntrustedHost: Host must be trusted. URL was: https://panel.my-app.com/api/auth/session. Read more at https://errors.authjs.dev#untrustedhost panel:start: at /app/apps/panel/.next/server/middleware.js:389:48416 panel:start: at ac (/app/apps/panel/.next/server/middleware.js:389:51116) panel:start: at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
补充信息
- 两个应用均为Next.js应用
- 共用相同的自定义认证中间件:
function useAuthMiddleware( middleware: CustomMiddleware, ): CustomMiddleware | NextMiddlewareResult { return auth((request) => { const response = NextResponse.next() if (isUnprotectedRoute(request.nextUrl.pathname)) return NextResponse.next() if (!request.auth) return NextResponse.redirect("https://console.my-app.com/login") return middleware(request, undefined, response) }) }
- 共用相同的
auth.config.ts配置:
export const Local = Credentials({ credentials: { email: {}, password: {}, }, authorize: async (credentials) => { const client = new FetchClient() try { const authBody = await client.post({ url: `https://api.my-app.com/auth-token`, data: { email: credentials.email, password: credentials.password, }, config: { headers: { 'Content-Type': 'application/json', }, }, }) return authBody } catch (error) { console.error(error) return null } }, }) // Define how we want the session token to be stored in our browser const cookies: NextAuthConfig['cookies'] = { sessionToken: { name: `session-token`, options: { httpOnly: true, sameSite: 'lax', path: '/', secure: useSecureCookies, domain: "console.my-app.com", }, }, } export default { providers: [Local, Google], secret: AUTH_SECRET, pages: { signIn: '/login', error: '/500', }, useSecureCookies, cookies, } satisfies NextAuthConfig
- 主应用环境变量:
AUTH_URL=https://console.my-app.com console.my-app.com为多区域架构,多个应用重写到主应用;panel.my-app.com为独立子域应用
疑问解答
1. 能否使用Auth.js为多个不同子域的Next.js应用实现跨域用户认证?
可以实现,但需要满足两个核心条件:
- 会话Cookie的
domain设置为父域(如.my-app.com),确保所有子域能共享该Cookie - 所有子域都被加入Auth.js的信任主机列表,避免触发
UntrustedHost错误
2. 若需将域名加入信任列表,该如何操作?
有两种可靠配置方式:
方式一:在Auth.js配置中添加trustHost选项
在auth.config.ts中指定信任的主机:
export default { // ...其他原有配置 // 生产环境建议指定具体域名数组,避免安全风险 trustHost: ["console.my-app.com", "panel.my-app.com"], // 开发环境可临时设为true,方便调试 // trustHost: true }
方式二:通过环境变量AUTH_TRUST_HOST配置
在两个应用的环境变量中添加:
# 生产环境指定具体域名,多个用逗号分隔 AUTH_TRUST_HOST=console.my-app.com,panel.my-app.com # 开发环境可设为true # AUTH_TRUST_HOST=true
3. 原本正常的认证为何突然失效?
大概率是以下原因之一:
- 信任主机配置变更:误修改了
trustHost配置或对应环境变量,导致panel.my-app.com被移除出信任列表 - Cookie域名限制:当前Cookie的
domain设为console.my-app.com,panel.my-app.com无法读取该Cookie;原本正常可能是之前配置的是父域.my-app.com,之后被修改 - Auth.js版本更新:部分版本对信任主机的校验逻辑做了调整,升级后未同步配置
- 环境变量覆盖:
panel.my-app.com的环境变量中新增了AUTH_URL或AUTH_TRUST_HOST,覆盖了全局统一配置
跨子域认证最佳实践
- 统一Cookie域名:将Cookie的
domain改为父域,确保所有子域能共享会话Cookie:
const cookies: NextAuthConfig['cookies'] = { sessionToken: { name: `session-token`, options: { httpOnly: true, sameSite: 'lax', path: '/', secure: useSecureCookies, domain: ".my-app.com", // 改为父域,注意开头的点 }, }, }
- 明确配置信任主机:生产环境务必指定具体信任域名,禁止使用
trustHost: true,避免安全风险 - 统一核心环境变量:两个应用共享
AUTH_SECRET、AUTH_TRUST_HOST等变量,避免配置不一致 - 优化中间件跳转逻辑:确保登录完成后能跳回原应用,修改中间件的跳转代码:
if (!request.auth) { const callbackUrl = encodeURIComponent(request.nextUrl.href) return NextResponse.redirect(`https://console.my-app.com/login?callbackUrl=${callbackUrl}`) }
- 验证Cookie共享:在浏览器开发者工具的Application标签下,检查两个子域是否能读取到同一个
session-tokenCookie
内容的提问来源于stack exchange,提问作者Malek Boubakri
相关产品推荐
相关产品推荐

