From 4492691ce24b76a9b428dd4e16e89505df8e3301 Mon Sep 17 00:00:00 2001 From: Jeffrey Leon Date: Thu, 6 Nov 2025 12:50:04 -0400 Subject: [PATCH 1/5] fix: update handlePkceVerifier to accept onlyConsume option for prevent code_challenge missing in authorize query --- src/runtime/server/lib/oauth/azureb2c.ts | 2 +- src/runtime/server/lib/oauth/kick.ts | 2 +- src/runtime/server/lib/oauth/zitadel.ts | 2 +- src/runtime/server/lib/utils.ts | 7 ++++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/runtime/server/lib/oauth/azureb2c.ts b/src/runtime/server/lib/oauth/azureb2c.ts index 71da9e28..03795c1b 100644 --- a/src/runtime/server/lib/oauth/azureb2c.ts +++ b/src/runtime/server/lib/oauth/azureb2c.ts @@ -81,7 +81,7 @@ export function defineOAuthAzureB2CEventHandler({ config, onSuccess, onError }: config.scope = [...new Set(config.scope)] // Create pkce verifier - const verifier = await handlePkceVerifier(event) + const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) const state = await handleState(event) if (!query.code) { diff --git a/src/runtime/server/lib/oauth/kick.ts b/src/runtime/server/lib/oauth/kick.ts index 016efa56..901c5ac2 100644 --- a/src/runtime/server/lib/oauth/kick.ts +++ b/src/runtime/server/lib/oauth/kick.ts @@ -61,7 +61,7 @@ export function defineOAuthKickEventHandler({ config, onSuccess, onError }: OAut } // Create pkce verifier - const verifier = await handlePkceVerifier(event) + const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) const redirectURL = config.redirectURL || getOAuthRedirectURL(event) diff --git a/src/runtime/server/lib/oauth/zitadel.ts b/src/runtime/server/lib/oauth/zitadel.ts index c2a85993..8fc353ea 100644 --- a/src/runtime/server/lib/oauth/zitadel.ts +++ b/src/runtime/server/lib/oauth/zitadel.ts @@ -70,7 +70,7 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O const redirectURL = config.redirectURL || getOAuthRedirectURL(event) // Create pkce verifier - const verifier = await handlePkceVerifier(event) + const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) const state = await handleState(event) if (!query.code) { diff --git a/src/runtime/server/lib/utils.ts b/src/runtime/server/lib/utils.ts index 699eda29..59ce6be7 100644 --- a/src/runtime/server/lib/utils.ts +++ b/src/runtime/server/lib/utils.ts @@ -181,10 +181,15 @@ function getRandomBytes(size: number = 32) { return getRandomValues(new Uint8Array(size)) } -export async function handlePkceVerifier(event: H3Event) { +export async function handlePkceVerifier( + event: H3Event, + { onlyConsume }: { onlyConsume?: boolean } = {}, +) { let verifier = getCookie(event, 'nuxt-auth-pkce') if (verifier) { deleteCookie(event, 'nuxt-auth-pkce') + } + if (onlyConsume) { return { code_verifier: verifier } } From bf546d8304110e21ddac0c3d7ce92bc7c4627110 Mon Sep 17 00:00:00 2001 From: Jeffrey Leon Date: Tue, 25 Nov 2025 09:13:43 -0400 Subject: [PATCH 2/5] fix: refactor handlePkceVerifier and handleState to accept onlyConsume option --- src/runtime/server/lib/oauth/azureb2c.ts | 5 +++-- src/runtime/server/lib/oauth/kick.ts | 3 ++- src/runtime/server/lib/oauth/zitadel.ts | 5 +++-- src/runtime/server/lib/utils.ts | 4 +++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/runtime/server/lib/oauth/azureb2c.ts b/src/runtime/server/lib/oauth/azureb2c.ts index 03795c1b..314d2754 100644 --- a/src/runtime/server/lib/oauth/azureb2c.ts +++ b/src/runtime/server/lib/oauth/azureb2c.ts @@ -81,8 +81,9 @@ export function defineOAuthAzureB2CEventHandler({ config, onSuccess, onError }: config.scope = [...new Set(config.scope)] // Create pkce verifier - const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) - const state = await handleState(event) + const onlyConsume = !!query.code + const verifier = await handlePkceVerifier(event, { onlyConsume }) + const state = await handleState(event, { onlyConsume }) if (!query.code) { // Redirect to Azure B2C Oauth page diff --git a/src/runtime/server/lib/oauth/kick.ts b/src/runtime/server/lib/oauth/kick.ts index 901c5ac2..19d894d0 100644 --- a/src/runtime/server/lib/oauth/kick.ts +++ b/src/runtime/server/lib/oauth/kick.ts @@ -61,7 +61,8 @@ export function defineOAuthKickEventHandler({ config, onSuccess, onError }: OAut } // Create pkce verifier - const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) + const onlyConsume = !!query.code + const verifier = await handlePkceVerifier(event, { onlyConsume }) const redirectURL = config.redirectURL || getOAuthRedirectURL(event) diff --git a/src/runtime/server/lib/oauth/zitadel.ts b/src/runtime/server/lib/oauth/zitadel.ts index 8fc353ea..e8219921 100644 --- a/src/runtime/server/lib/oauth/zitadel.ts +++ b/src/runtime/server/lib/oauth/zitadel.ts @@ -70,8 +70,9 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O const redirectURL = config.redirectURL || getOAuthRedirectURL(event) // Create pkce verifier - const verifier = await handlePkceVerifier(event, { onlyConsume: !!query.code }) - const state = await handleState(event) + const onlyConsume = !!query.code + const verifier = await handlePkceVerifier(event, { onlyConsume }) + const state = await handleState(event, { onlyConsume }) if (!query.code) { config.scope = config.scope || ['openid'] diff --git a/src/runtime/server/lib/utils.ts b/src/runtime/server/lib/utils.ts index 59ce6be7..8777c702 100644 --- a/src/runtime/server/lib/utils.ts +++ b/src/runtime/server/lib/utils.ts @@ -209,10 +209,12 @@ export async function handlePkceVerifier( } } -export async function handleState(event: H3Event) { +export async function handleState(event: H3Event, { onlyConsume }: { onlyConsume?: boolean } = {}) { let state = getCookie(event, 'nuxt-auth-state') if (state) { deleteCookie(event, 'nuxt-auth-state') + } + if (onlyConsume) { return state } From 67ab8fbff90d90263ccf86404afb897ca57484b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Leon Date: Tue, 2 Dec 2025 08:10:19 -0400 Subject: [PATCH 3/5] fix: remove onlyConsume option from handlePkceVerifier and handleState functions, and get the code directly from event query --- src/runtime/server/lib/oauth/azureb2c.ts | 5 ++--- src/runtime/server/lib/oauth/kick.ts | 3 +-- src/runtime/server/lib/oauth/zitadel.ts | 5 ++--- src/runtime/server/lib/utils.ts | 15 +++++++-------- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/runtime/server/lib/oauth/azureb2c.ts b/src/runtime/server/lib/oauth/azureb2c.ts index 314d2754..71da9e28 100644 --- a/src/runtime/server/lib/oauth/azureb2c.ts +++ b/src/runtime/server/lib/oauth/azureb2c.ts @@ -81,9 +81,8 @@ export function defineOAuthAzureB2CEventHandler({ config, onSuccess, onError }: config.scope = [...new Set(config.scope)] // Create pkce verifier - const onlyConsume = !!query.code - const verifier = await handlePkceVerifier(event, { onlyConsume }) - const state = await handleState(event, { onlyConsume }) + const verifier = await handlePkceVerifier(event) + const state = await handleState(event) if (!query.code) { // Redirect to Azure B2C Oauth page diff --git a/src/runtime/server/lib/oauth/kick.ts b/src/runtime/server/lib/oauth/kick.ts index 19d894d0..016efa56 100644 --- a/src/runtime/server/lib/oauth/kick.ts +++ b/src/runtime/server/lib/oauth/kick.ts @@ -61,8 +61,7 @@ export function defineOAuthKickEventHandler({ config, onSuccess, onError }: OAut } // Create pkce verifier - const onlyConsume = !!query.code - const verifier = await handlePkceVerifier(event, { onlyConsume }) + const verifier = await handlePkceVerifier(event) const redirectURL = config.redirectURL || getOAuthRedirectURL(event) diff --git a/src/runtime/server/lib/oauth/zitadel.ts b/src/runtime/server/lib/oauth/zitadel.ts index e8219921..c2a85993 100644 --- a/src/runtime/server/lib/oauth/zitadel.ts +++ b/src/runtime/server/lib/oauth/zitadel.ts @@ -70,9 +70,8 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: O const redirectURL = config.redirectURL || getOAuthRedirectURL(event) // Create pkce verifier - const onlyConsume = !!query.code - const verifier = await handlePkceVerifier(event, { onlyConsume }) - const state = await handleState(event, { onlyConsume }) + const verifier = await handlePkceVerifier(event) + const state = await handleState(event) if (!query.code) { config.scope = config.scope || ['openid'] diff --git a/src/runtime/server/lib/utils.ts b/src/runtime/server/lib/utils.ts index 8777c702..29769089 100644 --- a/src/runtime/server/lib/utils.ts +++ b/src/runtime/server/lib/utils.ts @@ -1,4 +1,4 @@ -import { type H3Event, deleteCookie, getCookie, setCookie } from 'h3' +import { type H3Event, deleteCookie, getCookie, getQuery, setCookie } from 'h3' import { getRequestURL } from 'h3' import { FetchError } from 'ofetch' import { snakeCase, upperFirst } from 'scule' @@ -181,15 +181,13 @@ function getRandomBytes(size: number = 32) { return getRandomValues(new Uint8Array(size)) } -export async function handlePkceVerifier( - event: H3Event, - { onlyConsume }: { onlyConsume?: boolean } = {}, -) { +export async function handlePkceVerifier(event: H3Event) { let verifier = getCookie(event, 'nuxt-auth-pkce') if (verifier) { deleteCookie(event, 'nuxt-auth-pkce') } - if (onlyConsume) { + const query = getQuery<{ code?: string }>(event) + if (query.code) { return { code_verifier: verifier } } @@ -209,12 +207,13 @@ export async function handlePkceVerifier( } } -export async function handleState(event: H3Event, { onlyConsume }: { onlyConsume?: boolean } = {}) { +export async function handleState(event: H3Event) { let state = getCookie(event, 'nuxt-auth-state') if (state) { deleteCookie(event, 'nuxt-auth-state') } - if (onlyConsume) { + const query = getQuery<{ code?: string }>(event) + if (query.code) { return state } From 26aa9301b288f97f5a15a598c3c4e5705a522c64 Mon Sep 17 00:00:00 2001 From: Jeffrey Leon Date: Tue, 2 Dec 2025 08:14:19 -0400 Subject: [PATCH 4/5] fix: add verifier and state checks in handlePkceVerifier and handleState functions --- src/runtime/server/lib/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/server/lib/utils.ts b/src/runtime/server/lib/utils.ts index 29769089..3a781e21 100644 --- a/src/runtime/server/lib/utils.ts +++ b/src/runtime/server/lib/utils.ts @@ -187,7 +187,7 @@ export async function handlePkceVerifier(event: H3Event) { deleteCookie(event, 'nuxt-auth-pkce') } const query = getQuery<{ code?: string }>(event) - if (query.code) { + if (verifier && query.code) { return { code_verifier: verifier } } @@ -213,7 +213,7 @@ export async function handleState(event: H3Event) { deleteCookie(event, 'nuxt-auth-state') } const query = getQuery<{ code?: string }>(event) - if (query.code) { + if (state && query.code) { return state } From 0a899e899367a3882c0da631e68372cf17c4bd06 Mon Sep 17 00:00:00 2001 From: Jeffrey Leon Date: Tue, 2 Dec 2025 08:16:28 -0400 Subject: [PATCH 5/5] fix: ensure verifier and state checks only proceed if query code is present --- src/runtime/server/lib/utils.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/runtime/server/lib/utils.ts b/src/runtime/server/lib/utils.ts index 3a781e21..84cd533f 100644 --- a/src/runtime/server/lib/utils.ts +++ b/src/runtime/server/lib/utils.ts @@ -185,10 +185,11 @@ export async function handlePkceVerifier(event: H3Event) { let verifier = getCookie(event, 'nuxt-auth-pkce') if (verifier) { deleteCookie(event, 'nuxt-auth-pkce') - } - const query = getQuery<{ code?: string }>(event) - if (verifier && query.code) { - return { code_verifier: verifier } + + const query = getQuery<{ code?: string }>(event) + if (query.code) { + return { code_verifier: verifier } + } } // Create new verifier @@ -211,10 +212,11 @@ export async function handleState(event: H3Event) { let state = getCookie(event, 'nuxt-auth-state') if (state) { deleteCookie(event, 'nuxt-auth-state') - } - const query = getQuery<{ code?: string }>(event) - if (state && query.code) { - return state + + const query = getQuery<{ code?: string }>(event) + if (query.code) { + return state + } } state = encodeBase64Url(getRandomBytes(8))