502 Bad Gateway在生产环境中使用Nextjs next-auth和URL '/api/auth/callback/cognito'
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);
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设置正确,以避免其他可能的错误。