You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next Auth自定义OIDC Provider的nonce校验失败问题求助

问题描述

我正在使用要求提供nonce的IDP(FranceConnect),Next Auth配置如下(已在authorization步骤传入自行生成的nonce):

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":"The following fields are missing or empty : nonce"}


解决方案

方案1:改用OIDC类型Provider(推荐)

FranceConnect是标准OpenID Connect服务,将Provider的type设为oidc后,NextAuth会自动处理nonce的生成、传递和验证,无需手动配置:

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

const authOptions: NextAuthOptions = {
    providers: [
        {
            id: 'franceconnect',
            name: 'FranceConnect',
            type: 'oidc',
            issuer: 'https://fcp.integ01.dev-franceconnect.fr',
            clientId: process.env.FRANCE_CONNECT_ID || 'undefined',
            clientSecret: process.env.FRANCE_CONNECT_SECRET || 'undefined',
            client: {
                authorization_signed_response_alg: 'HS256',
                id_token_signed_response_alg: 'HS256'
            },
            scope: 'openid given_name gender',
            redirectUri: 'http://localhost:3000/api/auth/callback/franceconnect',
            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)

方案2:手动动态生成nonce(不推荐)

如果必须手动控制nonce,需要确保每个请求的nonce唯一,且让NextAuth能跟踪验证:

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

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'
            },
            // 用函数动态生成授权参数,每个请求生成唯一nonce
            authorizationParams: () => {
                const nonce = `nonce${randomBytes(16).toString('hex')}`
                return {
                    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, profile }) {
            return token
        },
        async session({ session, token, user }) {
            return session
        },
    },
}

export default NextAuth(authOptions)

内容的提问来源于stack exchange,提问作者Valentine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:03:22