Skip to content

Commit b0e8bec

Browse files
committed
feat(validation): ✨ Improved aud field handling in validation process
1 parent e3a9ad2 commit b0e8bec

File tree

4 files changed

+30
-16
lines changed

4 files changed

+30
-16
lines changed

playground/nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default defineNuxtConfig({
3535
allowedClientAuthParameters: [
3636
'test',
3737
],
38+
validateAccessToken: true,
3839
},
3940
auth0: {
4041
audience: 'test-api-oidc',

src/runtime/server/lib/oidc.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ export function callbackEventHandler({ onSuccess }: OAuthConfig<UserSession>) {
177177
return sendRedirect(
178178
event,
179179
consentUrl,
180-
200,
180+
302,
181181
)
182182
}
183183
return oidcErrorHandler(event, 'Token request failed')
@@ -192,15 +192,20 @@ export function callbackEventHandler({ onSuccess }: OAuthConfig<UserSession>) {
192192
if ([config.audience as string, config.clientId].some(audience => accessToken.aud?.includes(audience) || idToken?.aud?.includes(audience)) && (config.validateAccessToken || config.validateIdToken)) {
193193
// Get OIDC configuration
194194
const openIdConfiguration = (config.openIdConfiguration && typeof config.openIdConfiguration === 'object') ? config.openIdConfiguration : typeof config.openIdConfiguration === 'string' ? await ofetch(config.openIdConfiguration) : await (config.openIdConfiguration!)(config)
195-
const validationOptions = { jwksUri: openIdConfiguration.jwks_uri as string, issuer: openIdConfiguration.issuer as string, ...config.audience && { audience: config.audience } }
196-
197-
tokens = {
198-
accessToken: config.validateAccessToken ? await validateToken(tokenResponse.access_token, validationOptions) : accessToken,
199-
...tokenResponse.refresh_token && { refreshToken: tokenResponse.refresh_token },
200-
...tokenResponse.id_token && { idToken: config.validateIdToken ? await validateToken(tokenResponse.id_token, validationOptions) : parseJwtToken(tokenResponse.id_token) },
195+
const validationOptions = { jwksUri: openIdConfiguration.jwks_uri as string, issuer: openIdConfiguration.issuer as string, ...config.audience && { audience: [config.audience, config.clientId] } }
196+
try {
197+
tokens = {
198+
accessToken: config.validateAccessToken ? await validateToken(tokenResponse.access_token, validationOptions) : accessToken,
199+
...tokenResponse.refresh_token && { refreshToken: tokenResponse.refresh_token },
200+
...tokenResponse.id_token && { idToken: config.validateIdToken ? await validateToken(tokenResponse.id_token, validationOptions) : parseJwtToken(tokenResponse.id_token) },
201+
}
202+
}
203+
catch (error) {
204+
return oidcErrorHandler(event, `[${provider}] Token validation failed: ${error}`)
201205
}
202206
}
203207
else {
208+
logger.info('Skipped token validation')
204209
tokens = {
205210
accessToken,
206211
...tokenResponse.refresh_token && { refreshToken: tokenResponse.refresh_token },
@@ -278,7 +283,7 @@ export function logoutEventHandler({ onSuccess }: OAuthConfig<UserSession>) {
278283
const logoutRedirectUri = logoutParams.logoutRedirectUri || config.logoutRedirectUri
279284

280285
// Set logout_hint and id_token_hint dynamic parameters if specified. According to https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
281-
const additionalLogoutParameters: Record<string, string> = config.additionalLogoutParameters || {}
286+
const additionalLogoutParameters: Record<string, string> = config.additionalLogoutParameters ? { ...config.additionalLogoutParameters } : {}
282287
if (config.additionalLogoutParameters) {
283288
const userSession = await getUserSession(event)
284289
Object.keys(config.additionalLogoutParameters).forEach((key) => {

src/runtime/server/utils/oidc.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import type { RefreshTokenRequest, TokenRequest, TokenRespose, UserSession } fro
33
import type { OidcProviderConfig } from './provider'
44
import { createConsola } from 'consola'
55
import { createDefu } from 'defu'
6-
import { createError } from 'h3'
6+
import { sendRedirect } from 'h3'
77
import { ofetch } from 'ofetch'
88
import { snakeCase } from 'scule'
99
import { normalizeURL } from 'ufo'
1010
import { textToBase64 } from 'undio'
1111
import { parseJwtToken } from './security'
12+
import { clearUserSession } from './session'
1213

1314
export function useOidcLogger() {
1415
return createConsola().withDefaults({ tag: 'nuxt-oidc-auth', message: '[nuxt-oidc-auth]:' })
@@ -23,6 +24,7 @@ export const configMerger = createDefu((obj, key, value) => {
2324
})
2425

2526
export async function refreshAccessToken(refreshToken: string, config: OidcProviderConfig) {
27+
const logger = useOidcLogger()
2628
// Construct request header object
2729
const headers: HeadersInit = {}
2830

@@ -77,6 +79,8 @@ export async function refreshAccessToken(refreshToken: string, config: OidcProvi
7779
config.optionalClaims.forEach(claim => parsedIdToken[claim] && ((user.claims as Record<string, unknown>)[claim] = (parsedIdToken[claim])))
7880
}
7981

82+
logger.info('Successfully refreshed token')
83+
8084
return {
8185
user,
8286
tokens,
@@ -123,8 +127,12 @@ export function convertObjectToSnakeCase(object: Record<string, any>) {
123127
}
124128

125129
export function oidcErrorHandler(event: H3Event, errorText: string, errorCode: number = 500) {
126-
throw createError({
127-
statusCode: errorCode,
128-
message: errorText,
129-
})
130+
const logger = useOidcLogger()
131+
clearUserSession(event, true)
132+
logger.error(errorText, 'code:', errorCode)
133+
return sendRedirect(
134+
event,
135+
'/',
136+
302,
137+
)
130138
}

src/runtime/server/utils/session.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ export async function setUserSession(event: H3Event, data: UserSession) {
4444
return session.data
4545
}
4646

47-
export async function clearUserSession(event: H3Event) {
47+
export async function clearUserSession(event: H3Event, skipHook: boolean = false) {
4848
const session = await _useSession(event)
4949
await useStorage('oidc').removeItem(session.id as string)
5050

51-
await sessionHooks.callHookParallel('clear', event)
51+
if (!skipHook)
52+
await sessionHooks.callHookParallel('clear', event)
5253

5354
await session.clear()
5455
deleteCookie(event, sessionName)
@@ -149,7 +150,6 @@ export async function getUserSession(event: H3Event) {
149150
// Automatic token refresh
150151
if (providerSessionConfigs[provider].automaticRefresh) {
151152
await refreshUserSession(event)
152-
logger.info('Successfully refreshed token')
153153
return userSession
154154
}
155155
await clearUserSession(event)

0 commit comments

Comments
 (0)