使用 next.js 进行下一次身份验证时出现 JWT_SESSION_ERROR

Zal*_*esh 3 authentication oauth-2.0 identityserver4 next.js next-auth

在本地开发中,登录工作正常,但在从我们的自定义 oauth 提供程序返回并在开发 URL(如https://dev-app.xyz.com)上进行生产构建时,下一个验证会出现以下错误

NEXTAUTH_SECRET 和 NEXTAUTH_URL env 变量也按照此https://next-auth.js.org/deployment设置

` authError { code: 'JWT_SESSION_ERROR', 元数据: { code: 'ERR_JWE_DECRYPTION_FAILED', name: 'JWEDecryptionFailed', message: '解密操作失败',

} }`

软件包版本

`“依赖项”:{

"@mui/icons-material": "^5.10.14",
"@mui/x-data-grid": "^5.17.14",
"@sentry/nextjs": "^7.23.0",
"@reduxjs/toolkit": "^1.9.1",
"applicationinsights": "^2.3.6",
"axios": "^1.2.0",
"moment": "^2.29.4",
"moment-timezone": "^0.5.38",
"net": "^1.0.2",
"next": "13.0.4",
"next-auth": "^4.18.4",
"nextjs-redirect": "^6.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-intl": "^6.2.1",
"react-redux": "^8.0.5",
"react-test-renderer": "^18.2.0",
"tls": "^0.0.1",
"v8": "^0.1.0"
Run Code Online (Sandbox Code Playgroud)

}, `

[...nextauth].ts 如下

export default async function auth(req: NextApiRequest, res: NextApiResponse) {
    if (!config?.payload) {
        try {
            const response = await fetch('url to fetch config dyamic');
            config = await response.json();
          
        } catch (error) {
            if (error) {
               
            }
        }
    }
    try {
        return await NextAuth(req, res, {
            providers: [
                {
                    id: appConst.OAUTH_ID,
                    name: 'Demo',
                    type: 'oauth',
                    checks: ['pkce', 'state'],
                    idToken: true,
                    wellKnown: `${config.payload.idtAuthorityUrl}${apiUrls.IDT_WELLKNOWN}`,
                    authorization: {
                        params: {
                            scope: config.payload.webAppIdtClientScope,
                        },
                    },
                    clientId: config.payload.webAppIdtClientId,
                    profile(profile) {
                        return {
                            id: 1,
                            ...profile,
                        };
                    },
                    clientSecret: config.payload.webAppIdtClientSecret,
                },
            ],
            pages: {
                signIn: apiUrls.AUTH_ERROR,
            },
            secret: process.env.NEXTAUTH_SECRET,
            debug: false,
            session: {
                strategy: 'jwt',
            },
            jwt: {
                secret: process.env.NEXTAUTH_SECRET
            },
            useSecureCookies: true,// using false while local development
            logger: {
                error(code, metadata) {
          
                    // eslint-disable-next-line no-console
                    console.log('authError', { code, metadata });
       
                },
            },
            callbacks: {
                async jwt({ token, account }) {
                    if (account) {
                        token.accessToken = account.access_token;
                        token.accessTokenExpire = account.expires_at
                            ? account.expires_at * 1000
                            : 0;
                        token.refreshToken = account?.refresh_token;
                        token.id_token = account?.id_token;
                        token.accessTokenIssuedAt = Date.now();
                    }
                    //  return token if not Access token expired
                    if (
                        token.accessTokenExpire &&
                        Date.now() < token.accessTokenExpire
                    ) {
                        return token;
                    }
                    //  Access token has expired, try to update it
                    return await getAccessToken(token, config.payload);
                },
                // eslint-disable-next-line require-await
                async session({ session, user, token }) {
                    if (token && typeof token.accessTokenExpire === 'number' && typeof token.accessTokenIssuedAt === 'number') {
                        const tempsession: any = session;
                        // session interval in seconds, It's accesstoken expire - 10 minutes
                        let interval = Math.round(((token.accessTokenExpire - token.accessTokenIssuedAt) - (60000 * 10)) / 1000);
                        if (interval < 300) {
                            interval = 2
                        }
                        tempsession.interval = interval;
                        return tempsession;
                    } else {
                        return session;
                    }
                },
            },
        });
    } catch (error) {
        if (error) {
   
            console.log('NextAuth', error);
          
        
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

小智 6

如果您遇到以下任何错误,请按照以下步骤操作,错误将得到修复,就像我的错误已修复一样。

\n
1. code: 'JWT_SESSION_ERROR' name: 'JWEDecryptionFailed\n\n2. MissingSecret [MissingSecretError]: Please define a `secret` in production.\n\n3.ERROR[next - auth][error][NO_SECRET];\n
Run Code Online (Sandbox Code Playgroud)\n

步骤 1 生成秘密

\n

为此,请在 Linux 下打开一个终端(在 Window Open Hyper 或 CMD 中)并键入:openssl rand -base64 32\n此命令的输出将是您的秘密,如下所示的字符串:Ey7nTKnggBc0bRN8WUjyShw2qzOZ6KW4fUyqcKBePxY=

\n

2-将此秘密放入环境变量中

\n

我建议您将此秘密放入环境变量中。您可以使用 .env 文件(或 .env.local)或直接使用 next.config.js 文件。这里我以我喜欢使用的 next.config.js 文件为例。在此文件中,添加包含值 NEXTAUTH_SECRET 和您的密码的行。\n我在 .env 文件中的示例:NEXTAUTH_SECRET='78zFZvyspgAIBXPKdA0AhFqcNWXX16/CEmBFOHU3iOg='

\n

3-在下一个身份验证配置中添加秘密

\n

将您的秘密设置为环境变量后,next-auth 必须能够访问它。在 NextJS 下,可以通过 process.env 对象在服务器端访问环境变量,我们在这里感兴趣的是 NEXTAUTH_SECRET 属性,\n在您的应用程序上,转到文件 /pages/api/auth/[... nextauth].js,并在与提供者和可能的回调相同的级别添加值:

\n
secret: process.env.NEXTAUTH_SECRET,\n
Run Code Online (Sandbox Code Playgroud)\n

4-重新启动构建

\n

最后,记住运行一个新的 npm run build,然后你\xe2\x80\x99就全部准备好了!

\n