502 使用 Nextjs next-auth 进行生产时出现错误网关,网址为“/api/auth/callback/cognito”

问题描述 投票:0回答:2

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

当我在本地运行它时,使用

next dev
next start
都可以正常工作。

当我在生产服务器(ubuntu,带有 nginx)上运行它时,它没有。

确切错误: 访问 Cognito 内置登录页面后,重定向 url

https://...../api/auth/callback/cognito?code=......&state=.....
显示 nginx 的默认 502 错误页面。

我检查过的内容:

  • 有关此主题的所有可能的 google 结果、github 问题和 stackoverflow 问题
  • 生产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);
typescript nginx next.js amazon-cognito next-auth
2个回答
18
投票

好吧,我最终自己弄清楚了,事实证明我没有正确读取我的 nginx 日志,一旦我这样做了,这并不是什么太难的事情......这就是我所做的:

最重要:

502 错误很可能与该请求的 nginx 错误日志中的

upstream sent too big header while reading response header from upstream
错误相对应。要解决此问题,请将其添加到您的配置中,在
/etc/nginx/nginx.conf
部分的
http {... } 
下...

proxy_buffers 8 16k;
proxy_buffer_size 32k;

(在这里找到了这个解决方案:https://stackoverflow.com/a/38758325/4205839

其他要尝试的事情:

上面的内容应该可以解决 502 错误,但是您可能仍然会在 next-auth 中遇到错误,这里有一些我在尝试解决此问题时发现的其他方法可以尝试...

在 AWS Cognito 中,尝试在 AWS Cognito 中创建并使用一个新的“应用程序客户端”,无需客户端密钥。

如果现在运行它,您将收到诸如

signin?error=OAuthCallback
client_secret_basic client authentication method requires a client_secret
之类的错误。因此,您还需要将
pages/api/auth/[...nextauth].ts
中的 cognito 配置更新为 ...

CognitoProvider({
clientId: COGNITO_CLIENT_ID,
      issuer: `https://cognito-idp.${COGNITO_AWS_REGION}.amazonaws.com/${COGNITO_POOL_ID!}`,
      clientSecret: "someString",
      client: {
           token_endpoint_auth_method: "none",
      },
})

我从这次讨论中发现:https://github.com/nextauthjs/next-auth/issues/2524

注意:如果您收到来自 Cognito 的类似

redirect_mismatch
错误,则意味着您尚未在 AWS Cognito 客户端应用程序设置中正确更新 URL,这是我在本地和实时之间切换时经常发现的情况调试。


0
投票

我在使用

ingress-nginx
控制器的 Kubernetes 环境中遇到了类似的问题。为了解决这个问题,我向 Ingress 资源添加了注释以增加 proxy-buffer-size。以下是合并必要注释后的最终版本:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-buffer-size: "8k"
...

此调整有助于改善较大响应的处理。请务必根据您的具体要求调整该值。

© www.soinside.com 2019 - 2024. All rights reserved.