502 Bad Gateway在生产环境中使用Nextjs next-auth和URL '/api/auth/callback/cognito'

10 浏览
0 Comments

502 Bad Gateway在生产环境中使用Nextjs next-auth和URL '/api/auth/callback/cognito'

我正在尝试发布一个使用'next-auth'和aws Cognito的nextjs应用程序。

当我在本地运行时,无论是使用next dev还是next start都能正常工作。

但是当我在生产服务器上运行(使用nginx的ubuntu服务器)时,就无法正常工作。

具体错误:

在访问Cognito内置登录页面后,重定向URL https://...../api/auth/callback/cognito?code=......&state=..... 显示了nginx的默认502错误页面。

我已经检查了以下内容:

  • 关于此主题的每一个谷歌搜索结果、GitHub问题和Stack Overflow问题
  • 生产环境下的next服务器和nginx服务器的错误日志,没有发现任何问题
  • 浏览器控制台日志,也没有发现任何问题

是的,在AWS Cognito中应用程序的Callback URL(s)设置为正确的URL(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
          // https://next-auth.js.org/configuration/callbacks#jwt-callback
          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);

0
0 Comments

502 Bad Gateway in production with Next.js next-auth with url '/api/auth/callback/cognito'是一个常见的错误,它通常是由于响应头的大小超过了nginx的限制所导致的。解决方法是在nginx的配置文件中增加以下内容:

proxy_buffers 8 16k;

proxy_buffer_size 32k;

这样可以增加nginx对响应头的缓冲区大小,从而解决502错误。这个解决方法可以在`/etc/nginx/nginx.conf`文件的`http {... }`部分进行配置。

除了以上解决502错误的方法外,还有一些其他的尝试方法。在AWS Cognito中,可以尝试创建一个没有客户端密钥的新的"App Client",并在项目中使用它。此外,还需要更新`pages/api/auth/[...nextauth].ts`文件中的cognito配置,将`token_endpoint_auth_method`设置为"none",并添加一个虚拟的客户端密钥。

如果在使用Cognito时收到类似于"redirect_mismatch"的错误,说明AWS Cognito客户端应用程序设置中的URL没有正确更新,这是在调试过程中经常遇到的问题。

在处理502错误时,还需注意检查日志是否有构建错误。AWS在构建失败时会返回502错误。

通过增加nginx的缓冲区大小和更新Cognito配置,可以解决502 Bad Gateway错误。同时,还需要确保AWS Cognito的URL设置正确,以避免其他可能的错误。

0