在AWS Lambda中使用serverless-http时NextAuth.js signIn()方法失效
问题场景
通过 AWS CDK 部署 NextJS + NextAuth.js 应用,使用 serverless-http 适配 Lambda 与 NextJS 的绑定。本地开发(yarn dev)或本地构建启动(yarn build && yarn start)时登录功能正常,但部署到 AWS 后:
- 点击「Sign In」跳转至
/api/auth/signin?callbackUrl=%2F,点击「Sign in with credentials」后页面仅刷新,无登录会话生成也不跳转首页 - 测试 Cognito Provider 时,点击登录出现「Unexpected token」错误,
signIn(...)函数尝试将登录页解析为 JSON
客户端与服务端均无报错,推测核心问题为域名、请求头或 Cookie 配置不匹配 Serverless 环境特性。
解决方案
1. 启用 NextAuth 的 Host 信任机制
NextAuth 默认仅信任 NEXTAUTH_URL 配置的域名,但 HttpApi 转发请求时的 Host 头可能为 API Gateway 内部域名,导致 NextAuth 无法正确识别回调地址。
修改 [...nextauth].ts,添加 trustHost 配置:
export const authOptions: NextAuthOptions = { // 原有配置... trustHost: true, // 允许 NextAuth 信任请求的 Host 头 // 其他配置... }
2. 修正 Serverless HTTP 的请求头传递
serverless-http 默认可能未正确传递真实 Host 头,导致 NextJS 无法识别自定义域名。修改 server.ts:
import { NextConfig } from "next"; import NextServer from "next/dist/server/next-server"; import serverless from "serverless-http"; // @ts-ignore import { config } from "./.next/required-server-files.json"; // 从环境变量获取真实域名,避免硬编码 localhost const hostname = process.env.NEXTAUTH_URL?.split('://')[1] || "localhost"; const nextServer = new NextServer({ hostname, port: 3000, dir: __dirname, dev: false, conf: { ...(config as NextConfig), }, }); // 配置 serverless-http 传递真实 Host 头 export const handler = serverless(nextServer.getRequestHandler(), { request: (req) => { req.headers.host = req.headers['x-forwarded-host'] || req.headers.host; }, });
3. 配置 HttpApi 的 CORS 与凭证支持
HttpApi 默认集成未开启凭证(Cookie)支持,导致浏览器无法保存 NextAuth 的会话 Cookie。修改 CDK 的 HttpApi 配置:
var httpApi = new HttpApi(this, "http-api", new HttpApiProps { DisableExecuteApiEndpoint = true, DefaultIntegration = new HttpLambdaIntegration("nextjs-route", function), DefaultDomainMapping = new DomainMappingOptions { DomainName = "myDomainName.com" }, // 添加 CORS 预飞行配置 CorsPreflight = new CorsPreflightOptions { AllowHeaders = new[] { "*" }, AllowMethods = new[] { CorsHttpMethod.GET, CorsHttpMethod.POST, CorsHttpMethod.PUT, CorsHttpMethod.DELETE, CorsHttpMethod.OPTIONS }, AllowOrigins = new[] { "https://myDomainName.com" }, // 明确指定自定义域名 AllowCredentials = true // 允许携带 Cookie 等凭证 } });
同时在 NextAuth 中显式配置 Cookie 域名:
export const authOptions: NextAuthOptions = { // 原有配置... cookies: { sessionToken: { name: `__Secure-next-auth.session-token`, options: { domain: ".myDomainName.com", // 带前缀点适配子域名(若有) path: "/", secure: true, httpOnly: true, sameSite: 'lax' } } }, // 其他配置... }
4. 优化构建脚本依赖完整性
原构建脚本仅手动复制 serverless-http 依赖,可能遗漏 NextAuth 运行所需的其他包。修改构建脚本,直接复用 NextJS standalone 打包的完整依赖:
#!/bin/bash BUILD_FOLDER=.dist yarn build rm -rf $BUILD_FOLDER # 复制 standalone 目录下所有内容(含完整 node_modules) cp -r .next/standalone/* $BUILD_FOLDER/ # 复制静态资源与公共文件 cp -r .next/static $BUILD_FOLDER/.next/ cp -r public $BUILD_FOLDER/ # 复制配置文件与编译后的 server.ts cp next.config.js $BUILD_FOLDER/ tsc server.ts --outDir $BUILD_FOLDER --esModuleInterop true
5. 升级 Lambda 运行时
确保 Lambda 使用 NODEJS_18_X 或更高版本(NextJS 13+ 推荐),避免版本兼容问题。同时确认 NEXTAUTH_SECRET 为有效随机字符串(可通过 openssl rand -hex 32 生成)。
内容的提问来源于stack exchange,提问作者downloadmoreram

