next.js - Next Auth 自定义提供商 OIDC 随机数检查

标签 next.js openid-connect next-auth nonce

我正在使用需要随机数的 IDP 我的 nextauth 是这样的(请注意,我在授权步骤中通过了我的随机数):

import NextAuth, { NextAuthOptions } from 'next-auth'

const randomString = (length: number) => {
    let text = ''
    let possible =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    for (let i = 0; i < length; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length))
    }
    return text
}
const nonce = `nonce${randomString(32)}`
const authOptions: NextAuthOptions = {
    providers: [
        {
            issuer: 'https://fcp.integ01.dev-franceconnect.fr',
            id: 'franceconnect',
            clientSecret: process.env.FRANCE_CONNECT_SECRET || 'undefined',
            clientId: process.env.FRANCE_CONNECT_ID || 'undefined',
            name: 'FranceConnect',
            type: 'oauth',
            idToken: true,
            client: {
                authorization_signed_response_alg: 'HS256',
                id_token_signed_response_alg: 'HS256'
            },
            authorization: {
                url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize',
                params: {
                    scope: 'openid given_name gender',
                    nonce,
                    redirect_uri: `http://localhost:3000/api/auth/callback/franceconnect`,
                },
            },
            token:`https://fcp.integ01.dev-franceconnect.fr/api/v1/token`,                    
            userinfo:
                'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo',
            profile(profile) {
                console.log(profile)
                return profile
            },
        },
    ],
    debug: true,
    secret: 'hdh-secret',
    callbacks: {
        async jwt({ token, account }) {
            return token
        },
        async session({ session, token, user }) {
            return session
        },
    },
}

export default NextAuth(authOptions)

我遇到了这个错误:

[next-auth][error][CALLBACK_OAUTH_ERROR]
https://next-auth.js.org/errors#callback_oauth_error nonce mismatch, expected undefined, got: nonceZDBoVu2bD1rRESxh7y4kgZ76A6NiP22e RPError: nonce mismatch, expected undefined, got: nonceZDBoVu2bD1rRESxh7y4kgZ76A6NiP22e
    at Client.validateIdToken (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\openid-client\lib\client.js:784:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Client.callback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\openid-client\lib\client.js:487:7)
    at async oAuthCallback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\lib\oauth\callback.js:114:16)
    at async Object.callback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\routes\callback.js:50:11)
    at async NextAuthHandler (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\index.js:186:28)
    at async NextAuthNextHandler (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\next\index.js:23:19)
    at async C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\next\index.js:59:32
    at async Object.apiResolver (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next\dist\server\api-utils\node.js:179:9)
    at async DevServer.runApi (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next\dist\server\next-server.js:381:9) {
  name: 'OAuthCallbackError',
  code: undefined
}

如果我删除 nonce,我会从 IDP 收到此错误:{"status":"fail","message":"以下字段丢失或为空:nonce"} 我该如何告诉下一个身份验证使用随机数?

最佳答案

我设法通过自己执行 token 和用户信息请求(感谢请求方法)来使其工作。 这是最终的代码:

providers: [
    {
        issuer: 'https://fcp.integ01.dev-franceconnect.fr',
        id: 'franceconnect',
        clientSecret: process.env.FRANCE_CONNECT_SECRET || 'undefined',
        clientId: process.env.FRANCE_CONNECT_ID || 'undefined',
        name: 'FranceConnect',
        type: 'oauth',
        authorization: {
            url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize',
            params: {
                scope: 'openid profile email',
                nonce,
                redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/franceconnect`,
            },
        },
        token: {
            async request(context) {
                const body = {
                    grant_type: 'authorization_code',
                    redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/franceconnect`,
                    client_id: process.env.FRANCE_CONNECT_ID || 'undefined',
                    client_secret:
                        process.env.FRANCE_CONNECT_SECRET || 'undefined',
                    code: context.params.code || 'undefined',
                }
                const data = new URLSearchParams(body).toString()
                try {
                    const r = await axios({
                        method: 'POST',
                        headers: {
                            'content-type':
                                'application/x-www-form-urlencoded',
                        },
                        data,
                        url: `https://fcp.integ01.dev-franceconnect.fr/api/v1/token`,
                    })
                    return { tokens: r.data }
                } catch (err: any) {
                    console.error(err)
                    throw new Error(err)
                }
            },
        },
        userinfo: {
            url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo',
            params: { schema: 'openid' },
            async request(context) {
                const r = await axios({
                    method: 'GET',
                    url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo?schema=openid',
                    headers: {
                        Authorization: `Bearer ${context.tokens.access_token}`,
                    },
                })
                return r.data
            },
        },
        profile(profile) {
            return {
                ...profile,
                name: `${profile.given_name} ${profile.family_name}`,
                id: profile.email,
            }
        },
    },
],

关于next.js - Next Auth 自定义提供商 OIDC 随机数检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73345086/

相关文章:

reactjs - 如何在react-froala中与nextjs一起使用许可证 key

javascript - 如何在使用 AnimatePresence 包装的 Next.js 页面中导航并滚动到具有 ID 的元素

security - 我需要在基于 cookie 的 API 中使用 CSRF token 吗?

javascript - 下一个 js : next auth provider + redux provider

reactjs - NextLink 动态路由在动态路由中不起作用

reactjs - 在 NextJS 中使用绝对导入后 VSCode 自动导入不起作用

java - Spring boot OIDC刷新 token 场景

azure - 具有 Microsoft 身份平台身份验证的 Web API

oauth-2.0 - 引用 token 是否需要刷新 token ?

reactjs - 无法在不稳定的 getServerSession 处读取未定义的属性(读取 'secret' )