Skip to content

NextAuth.js 配置子域名共享认证

1. 问题背景

1.1 跨子域名认证需求

在开发多子域名应用时,我们经常需要实现跨子域名的身份认证。例如:

  • app.example.com - 主应用
  • admin.example.com - 管理后台
  • api.example.com - API 服务

我们希望用户在其中一个子域名登录后,其他子域名也能自动识别用户的登录状态。

1.2 NextAuth.js 默认行为

NextAuth.js 默认情况下不支持跨子域名共享 Cookie,这意味着用户需要在每个子域名分别登录。通过配置 cookies 选项,我们可以实现跨子域名的认证共享。

2. 配置方案

2.1 核心配置

创建或编辑 pages/api/auth/[...nextauth].ts 文件:

ts
import NextAuth from 'next-auth'
import GitHubProvider from 'next-auth/providers/github'

// 判断是否在生产环境(HTTPS)
const useSecureCookies = !!process.env.VERCEL_URL

export default NextAuth({
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_ID as string,
      clientSecret: process.env.GITHUB_SECRET as string,
    }),
  ],
  secret: process.env.SECRET as string,
  cookies: {
    sessionToken: {
      name: `${useSecureCookies ? '__Secure-' : ''}next-auth.session-token`,
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        // 关键配置:设置为顶级域名,前面加点表示所有子域名共享
        domain: '.example.com',  // 替换为你的域名
        secure: useSecureCookies,
      },
    },
  },
})

2.2 配置说明

关键配置项解释:

  1. domain:设置为 .example.com 格式(注意前面的点),允许所有子域名共享 Cookie
  2. httpOnly:设置为 true,防止 JavaScript 访问 Cookie,提升安全性
  3. sameSite:设置为 'lax',在大多数跨站请求中发送 Cookie
  4. secure:在 HTTPS 环境下设置为 true
  5. useSecureCookies:根据环境自动判断是否使用安全 Cookie

2.3 环境变量配置

.env.local 文件中配置:

bash
# GitHub OAuth 配置
GITHUB_ID=your_github_client_id
GITHUB_SECRET=your_github_client_secret

# NextAuth 密钥
SECRET=your_secret_key

# 生产环境 URL(Vercel 会自动设置)
VERCEL_URL=example.com

3. 完整示例

3.1 克隆官方示例

Vercel 提供了完整的子域名认证示例,可以直接克隆使用:

可以克隆 官方示例 来查看完整的配置。

bash
pnpm create next-app --example https://github.com/vercel/examples/tree/main/solutions/subdomain-auth subdomain-auth
cd subdomain-auth
pnpm dev

3.2 使用其他认证提供商

NextAuth.js 支持多种认证提供商,配置方式类似:

ts
import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
import EmailProvider from 'next-auth/providers/email'

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_ID,
      clientSecret: process.env.GOOGLE_SECRET,
    }),
    EmailProvider({
      server: process.env.EMAIL_SERVER,
      from: process.env.EMAIL_FROM,
    }),
  ],
  // ... 其他配置
})

4. 注意事项

4.1 安全考虑

  1. HTTPS 要求:生产环境必须使用 HTTPS,否则无法设置 secure Cookie
  2. 域名验证:确保只在可信的子域名下使用
  3. Cookie 大小:注意 Cookie 大小限制(通常为 4KB)
  4. 跨站请求:根据需求合理设置 sameSite 属性

4.2 本地开发

本地开发时,可以:

  1. 使用 127.0.0.1 而不是 localhost(某些浏览器对 localhost 有特殊处理)
  2. 配置本地 hosts 文件模拟子域名
  3. 使用 ngrok 等工具创建临时域名测试

4.3 常见问题

Q: Cookie 没有在子域名间共享?

A: 检查以下几点:

  • domain 是否正确设置为 .example.com 格式
  • 浏览器是否支持跨域 Cookie
  • HTTPS 环境下是否正确设置 secure 属性

Q: 如何调试 Cookie?

A:

  • 使用浏览器开发者工具的 Application/Storage 标签查看 Cookie
  • 检查 Cookie 的 domain、path、secure 等属性是否正确

5. 参考资源