You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境Next.js集成NextAuth+Cognito回调遇502 Bad Gateway错误

问题:Next.js集成NextAuth+AWS Cognito生产环境Nginx 502错误

本地使用next dev或next start运行完全正常,但在Ubuntu搭配Nginx的生产服务器上,从Cognito内置登录页重定向至https://...../api/auth/callback/cognito?code=......&state=.....时,出现Nginx默认502错误页面。

已完成排查:

  • 查阅过相关谷歌搜索结果、GitHub议题及StackOverflow问题
  • 生产环境Next服务器与Nginx服务器的错误日志无异常
  • 浏览器控制台日志无异常
  • AWS Cognito中应用的Callback URL(s)已设置为正确地址(https://......./api/auth/callback/cognito)

相关代码

middleware.ts

export { default } from "next-auth/middleware";

export const config = { matcher: ["/dashboard/:path*"] };

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  compiler: {
    styledComponents: true,
   
  },
};

module.exports = nextConfig;

pages/api/auth/[...nextauth].ts

import CognitoProvider from "next-auth/providers/cognito";
import NextAuth, { NextAuthOptions, Session } from "next-auth";
import {
  AuthFlowType,
  CognitoIdentityProviderClient,
  InitiateAuthCommand,
} from "@aws-sdk/client-cognito-identity-provider";
import { JWT } from "next-auth/jwt";

const COGNITO_AWS_REGION = process.env.COGNITO_AWS_REGION;
const COGNITO_POOL_ID = process.env.COGNITO_POOL_ID;
const COGNITO_CLIENT_ID = process.env.COGNITO_CLIENT_ID;
const COGNITO_CLIENT_SECRET = process.env.COGNITO_CLIENT_SECRET;
const NEXTAUTH_SECRET = process.env.NEXTAUTH_SECRET;
const NEXTAUTH_URL = process.env.NEXTAUTH_URL;
if (!COGNITO_AWS_REGION) throw new Error("REGION is not set");
if (!COGNITO_CLIENT_ID) throw new Error("COGNITO_CLIENT_ID is not set");
if (!COGNITO_POOL_ID) throw new Error("COGNITO_USER_POOL_ID is not set");
if (!COGNITO_CLIENT_SECRET) throw new Error("COGNITO_CLIENT_SECRET is not set");
if (!NEXTAUTH_SECRET) throw new Error("NEXTAUTH_SECRET is not set");
if (!NEXTAUTH_URL) throw new Error("NEXTAUTH_URL is not set");

const refreshCognitoAccessToken = async (token: JWT) => {
  const client = new CognitoIdentityProviderClient({
    region: COGNITO_AWS_REGION,
  });
  const command = new InitiateAuthCommand({
    AuthFlow: AuthFlowType.REFRESH_TOKEN_AUTH,
    ClientId: COGNITO_CLIENT_ID,
    AuthParameters: {
      REFRESH_TOKEN: token.refreshToken as string,
    },
  });
  const response = await client.send(command);
  return response.AuthenticationResult;
};

export const authOptions: NextAuthOptions = {
  secret: NEXTAUTH_SECRET,
  // @ts-expect-error -- this property is not documented properly
  site: NEXTAUTH_URL,
  providers: [
    CognitoProvider({
      clientId: COGNITO_CLIENT_ID!,
      issuer: `https://cognito-idp.${COGNITO_AWS_REGION}.amazonaws.com/${COGNITO_POOL_ID!}`,
      clientSecret: process.env.COGNITO_CLIENT_SECRET!,
      
    }),
  ],
  callbacks: {
    jwt: async ({ token, account, user }) => {
      // Initial sign in
      if (account && user) {
        return {
          // save token to session for authenticating to AWS
          accessToken: account.access_token,
          accessTokenExpires: account.expires_at
            ? account.expires_at * 1000
            : 0,
          refreshToken: account.refresh_token,
          user,
        };
      }

      // Return previous token if the access token has not expired yet
      if (Date.now() < (token as unknown as Session).accessTokenExpires) {
        return token;
      }

      // Access token has expired, try to update it
      const refreshedTokens = await refreshCognitoAccessToken(token);
      return {
        ...token,
        accessToken: refreshedTokens?.AccessToken,
        accessTokenExpires: refreshedTokens?.ExpiresIn
          ? Date.now() + refreshedTokens?.ExpiresIn * 1000
          : 0,
        refreshToken: refreshedTokens?.RefreshToken ?? token.refreshToken, // Fall back to old refresh token
      };
    },

    session: async ({ session, token }) => {
      if (!session?.user || !token?.accessToken) {
        console.error("No accessToken found on token or session");
        return session;
      }
      session.user = token.user as Session["user"];
      session.accessToken = token.accessToken as string;
      session.error = token.error as string | undefined;

      return session;
    },
    redirect: async ({ url, baseUrl }) => {
      // allows any url
      if (url.startsWith("/")) return `${baseUrl}${url}`;
      return url;
    },
  },
};

export default NextAuth(authOptions);

排查与解决方案

1. Nginx反向代理配置问题

502错误核心原因通常是Nginx无法连接到上游Next.js服务器,检查以下配置点:

  • 确认proxy_pass指向的Next.js端口正确(默认3000,若自定义端口需对应)
  • 添加必要的请求头传递,避免Next.js无法识别真实请求地址:
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    
  • 增大client_max_body_size,Cognito回调的URL参数可能较长,建议设置为client_max_body_size 20m;

完整Nginx配置示例:

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /path/to/your-cert.pem;
    ssl_certificate_key /path/to/your-key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 20m;
    }
}

2. Next.js生产服务器稳定性与环境变量

  • 使用pm2或systemd托管Next.js进程,避免服务器意外退出导致Nginx无法连接
  • 确认生产环境NEXTAUTH_URL设置为完整HTTPS地址(如https://your-domain.com),与Cognito回调地址一致
  • 检查NEXTAUTH_SECRET是否与本地开发环境一致,密钥不一致会导致会话签名验证失败

3. NextAuth与Cognito配置优化

  • 移除authOptions中的site属性,NextAuth v4已废弃该属性,仅需通过NEXTAUTH_URL环境变量配置站点地址,旧属性可能导致回调地址生成异常
  • 检查Cognito用户池App Client设置:
    • Allowed OAuth Flows需包含Authorization code grant
    • Allowed OAuth Scopes需包含openid、email等必要权限

4. 网络与防火墙检查

  • 确认服务器防火墙开放Next.js端口(默认3000),允许本地Nginx访问
  • 若Cognito设置了IP白名单,需将生产服务器公网IP加入白名单,避免回调请求被拦截

内容的提问来源于stack exchange,提问作者Sheldonfrith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:15:32