I'm using an IDP that requires a nonce I have my nextauth like this (note that i passed my nonce in the authorization step) :
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)
I'm having this error :
[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
}
If I remove the nonce
I got this error from the IDP : {"status":"fail","message":"The following fields are missing or empty : nonce"}
How am I supposed to tell next auth to use a nonce ?
I manage to make it works by doing myself the token and userinfo requests (thanks to request method). Here is the final code :
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,
}
},
},
],