Skip to content

Commit 3b28a3f

Browse files
committed
feat(session): ✨ Tokens are now exposed via. userdata not in session cookie
1 parent 19bd6a7 commit 3b28a3f

File tree

9 files changed

+44
-26
lines changed

9 files changed

+44
-26
lines changed

playground/nuxt.config.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ export default defineNuxtConfig({
3232
additionalLogoutParameters: {
3333
logoutHint: '',
3434
},
35-
exposeIdToken: true,
36-
exposeAccessToken: false,
3735
allowedClientAuthParameters: [
3836
'test',
3937
],
@@ -65,7 +63,6 @@ export default defineNuxtConfig({
6563
clientId: '',
6664
clientSecret: '',
6765
redirectUri: 'http://localhost:3000/auth/keycloak/callback',
68-
exposeAccessToken: false,
6966
userNameClaim: 'preferred_username',
7067
},
7168
cognito: {
@@ -75,6 +72,7 @@ export default defineNuxtConfig({
7572
scope: ['openid', 'email', 'profile'],
7673
logoutRedirectUri: 'https://google.com',
7774
baseUrl: '',
75+
exposeIdToken: true,
7876
}
7977
},
8078
session: {

src/runtime/composables/oidcAuth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function useOidcAuth() {
3131
Accept: 'text/json',
3232
},
3333
method: 'POST',
34-
}).catch(() => (undefined)) as UserSession)
34+
}).catch(() => login()) as UserSession)
3535
}
3636

3737
/**

src/runtime/providers/cognito.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ export const cognito = defineOidcProvider<OidcProviderConfig, CognitoRequiredFie
3636
automaticRefresh: true,
3737
expirationThreshold: 240,
3838
},
39+
exposeIdToken: true,
3940
logoutRedirectParameterName: 'logout_uri',
4041
})

src/runtime/providers/entra.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export const entra = defineOidcProvider<EntraProviderConfig, EntraIdRequiredFiel
6262
openIdConfig.issuer = [`https://${parsedUrl.host}/${tenantId}/v2.0`, openIdConfig.issuer]
6363
return openIdConfig
6464
},
65+
sessionConfiguration: {
66+
expirationCheck: true,
67+
automaticRefresh: true,
68+
expirationThreshold: 1800,
69+
},
6570
validateAccessToken: false,
6671
validateIdToken: true,
6772
})

src/runtime/providers/keycloak.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ export const keycloak = defineOidcProvider<KeycloakProviderConfig, KeycloakRequi
5050
additionalLogoutParameters: {
5151
idTokenHint: '',
5252
},
53+
sessionConfiguration: {
54+
expirationCheck: true,
55+
automaticRefresh: true,
56+
expirationThreshold: 240,
57+
},
5358
validateAccessToken: true,
5459
validateIdToken: false,
5560
exposeIdToken: true,

src/runtime/server/lib/oidc.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,20 +243,14 @@ export function callbackEventHandler({ onSuccess }: OAuthConfig<UserSession>) {
243243
config.optionalClaims.forEach(claim => parsedIdToken[claim] && ((user.claims as Record<string, unknown>)[claim] = (parsedIdToken[claim])))
244244
}
245245

246-
// Expose access token
247-
if (config.exposeAccessToken)
248-
user.accessToken = tokenResponse.access_token
249-
250-
if (config.exposeIdToken)
251-
user.idToken = tokenResponse.id_token
252-
253-
if (tokenResponse.refresh_token) {
246+
if (tokenResponse.refresh_token || config.exposeAccessToken || config.exposeIdToken) {
254247
const tokenKey = process.env.NUXT_OIDC_TOKEN_KEY as string
255248
const persistentSession: PersistentSession = {
256249
exp: accessToken.exp as number,
257250
iat: accessToken.iat as number,
258251
accessToken: await encryptToken(tokenResponse.access_token, tokenKey),
259-
refreshToken: await encryptToken(tokenResponse.refresh_token, tokenKey),
252+
...tokenResponse.refresh_token && { refreshToken: await encryptToken(tokenResponse.refresh_token, tokenKey) },
253+
...tokenResponse.id_token && { idToken: await encryptToken(tokenResponse.id_token, tokenKey) },
260254
}
261255
const userSessionId = await getUserSessionId(event)
262256
await useStorage('oidc').setItem<PersistentSession>(userSessionId, persistentSession)
@@ -282,7 +276,7 @@ export function logoutEventHandler({ onSuccess }: OAuthConfig<UserSession>) {
282276
const logoutRedirectUri = logoutParams.logoutRedirectUri || config.logoutRedirectUri || `${getRequestURL(event).protocol}//${getRequestURL(event).host}`
283277

284278
// Set logout_hint and id_token_hint dynamic parameters if specified. According to https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
285-
const additionalLogoutParameters: Record<string, string> = {}
279+
const additionalLogoutParameters: Record<string, string> = config.additionalLogoutParameters || {}
286280
if (config.additionalLogoutParameters) {
287281
const userSession = await getUserSession(event)
288282
Object.keys(config.additionalLogoutParameters).forEach((key) => {

src/runtime/server/utils/oidc.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ export async function refreshAccessToken(refreshToken: string, config: OidcProvi
5656
}
5757

5858
// Construct tokens object
59-
const tokens: Record<'refreshToken' | 'accessToken', string> = {
59+
const tokens: Record<'refreshToken' | 'accessToken' | 'idToken', string> = {
6060
refreshToken: tokenResponse.refresh_token || refreshToken,
6161
accessToken: tokenResponse.access_token,
62+
idToken: tokenResponse.id_token || '',
6263
}
6364

6465
// Construct user object
@@ -75,13 +76,6 @@ export async function refreshAccessToken(refreshToken: string, config: OidcProvi
7576
config.optionalClaims.forEach(claim => parsedIdToken[claim] && ((user.claims as Record<string, unknown>)[claim] = (parsedIdToken[claim])))
7677
}
7778

78-
// Expose tokens
79-
if (config.exposeAccessToken)
80-
user.accessToken = tokenResponse.access_token
81-
82-
if (config.exposeIdToken)
83-
user.idToken = tokenResponse.id_token
84-
8579
return {
8680
user,
8781
tokens,

src/runtime/server/utils/session.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,19 @@ export async function refreshUserSession(event: H3Event) {
9292
iat: accessToken.iat || Math.trunc(Date.now() / 1000),
9393
accessToken: await encryptToken(tokens.accessToken, tokenKey),
9494
refreshToken: await encryptToken(tokens.refreshToken, tokenKey),
95+
...tokens.idToken && { idToken: await encryptToken(tokens.idToken, tokenKey) },
9596
}
9697

9798
await useStorage('oidc').setItem<PersistentSession>(session.id as string, updatedPersistentSession)
98-
await session.update(defu(user as UserSession, session.data))
99+
const { accessToken: _accessToken, idToken: _idToken, ...userWithoutToken } = user
99100

100-
return session.data
101+
await session.update(defu(userWithoutToken as UserSession, session.data))
102+
103+
return {
104+
...session.data,
105+
...(tokens.accessToken && (useRuntimeConfig(event).oidc.providers[provider]?.exposeAccessToken || providerPresets[provider].exposeAccessToken)) && { accessToken: tokens.accessToken },
106+
...(tokens.idToken && (useRuntimeConfig(event).oidc.providers[provider]?.exposeIdToken || providerPresets[provider].exposeIdToken)) && { idToken: tokens.idToken },
107+
}
101108
}
102109

103110
// Deprecated, please use getUserSession
@@ -154,6 +161,19 @@ export async function getUserSession(event: H3Event) {
154161
})
155162
}
156163
}
164+
// Expose tokens if configured
165+
if (useRuntimeConfig(event).oidc.providers[provider]?.exposeAccessToken || providerPresets[provider].exposeAccessToken) {
166+
const persistentSession = await useStorage('oidc').getItem<PersistentSession>(session.id as string) as PersistentSession | null
167+
const tokenKey = process.env.NUXT_OIDC_TOKEN_KEY as string
168+
if (persistentSession)
169+
userSession.accessToken = await decryptToken(persistentSession.accessToken, tokenKey)
170+
}
171+
if (useRuntimeConfig(event).oidc.providers[provider]?.exposeIdToken || providerPresets[provider].exposeIdToken) {
172+
const persistentSession = await useStorage('oidc').getItem<PersistentSession>(session.id as string) as PersistentSession | null
173+
const tokenKey = process.env.NUXT_OIDC_TOKEN_KEY as string
174+
if (persistentSession?.idToken)
175+
userSession.idToken = await decryptToken(persistentSession.idToken, tokenKey) || undefined
176+
}
157177
return userSession
158178
}
159179

@@ -169,7 +189,7 @@ function _useSession(event: H3Event) {
169189
Object.keys(useRuntimeConfig(event).oidc.providers).map(
170190
key => key as ProviderKeys,
171191
).forEach(
172-
key => providerSessionConfigs[key] = defu(useRuntimeConfig(event).oidc.providers[key]?.sessionConfiguration, {
192+
key => providerSessionConfigs[key] = defu(useRuntimeConfig(event).oidc.providers[key]?.sessionConfiguration, providerPresets[key].sessionConfiguration, {
173193
automaticRefresh: useRuntimeConfig(event).oidc.session.automaticRefresh,
174194
expirationCheck: useRuntimeConfig(event).oidc.session.expirationCheck,
175195
expirationThreshold: useRuntimeConfig(event).oidc.session.expirationThreshold,

src/runtime/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ export interface PersistentSession {
102102
exp: number
103103
iat: number
104104
accessToken: EncryptedToken
105-
refreshToken: EncryptedToken
105+
refreshToken?: EncryptedToken
106+
idToken?: EncryptedToken
106107
}
107108

108109
export interface TokenRequest {

0 commit comments

Comments
 (0)