Skip to content

Commit

Permalink
feat(session): ✨ Added exposeAccessToken setting; Exposed expireAt pr…
Browse files Browse the repository at this point in the history
…operty
  • Loading branch information
itpropro committed Jan 11, 2024
1 parent f190e43 commit 4162eda
Show file tree
Hide file tree
Showing 10 changed files with 44 additions and 5 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,22 @@ const { logout, currentProvider } = useOidcAuth()
</template>
```
### User object
The above composable functions grant access to a user object with the following properties:
| Name | Type | Description |
|---|---|---|---|
| provider | `string` | Name of provider used to login the current session |
| canRefresh | `boolean` | If the current session exposed a refresh token |
| loggedInAt | `number` | Login timestamp in second precision |
| updatedAt | `number` | Refresh timestamp in second precision |
| expireAt | `number` | Session expiration timestamp in second precision. Either loggedInAt plus session maxAge or exp of access token if available. |
| providerInfo | `Record<string, unknown>` | Additional information coming from the providers userinfo endpoint |
| userName | `string` | Coming either from the provider or from the configured mapped claim |
| claims | `Record<string, unknown>` | Additional optional claims from the id token, if `optionalClaims` setting is configured. |
| accessToken | `string` | Exposed access token, only existent when `exposeAccessToken` is configured. |
## Server Utils
The following helpers are auto-imported in your `server/` directory.
Expand Down Expand Up @@ -363,6 +379,7 @@ You can theoretically register a hook that overwrites internal session fields li
| validateAccessToken | `boolean` (optional) | `true` | Validate access token. |
| validateIdToken | `boolean` (optional) | `true` | Validate id token. |
| encodeRedirectUri | `boolean` (optional) | `false` | Encode redirect uri query parameter in authorization request. Only for compatibility with services that don't implement proper parsing of query parameters. |
| exposeAccessToken | `boolean` (optional) | `false` | Expose access token to the client within session object |
#### `session`
Expand Down
6 changes: 6 additions & 0 deletions playground/composables/useProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export const useProviders = (currentProvider: string) => {
disabled: Boolean(currentProvider === 'keycloak'),
icon: 'i-simple-icons-cncf',
},
{
label: 'Generic OIDC',
name: 'oidc',
disabled: Boolean(currentProvider === 'oidc'),
icon: 'i-simple-icons-openid',
},
])
return {
providers,
Expand Down
2 changes: 1 addition & 1 deletion playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default defineNuxtConfig({
},
session: {
expirationCheck: true,
automaticRefresh: true,
automaticRefresh: false,
},
middleware: {
globalMiddlewareEnabled: true,
Expand Down
4 changes: 2 additions & 2 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { providers } = useProviders(currentProvider.value as string)
</script>

<template>
<div class="w-full grid grid-cols-2 justify-center items-center">
<div class="w-full grid grid-cols-2">
<div class="col-start-1 flex flex-col gap-4 items-center">
<p class="text-xl">
Login with
Expand Down Expand Up @@ -56,7 +56,7 @@ const { providers } = useProviders(currentProvider.value as string)
<span class="font-bold text-base">
{{ `${key}` }}
</span>
<p class="text-sm pb-3">
<p class="text-sm pb-3 break-all">
{{ value }}
</p>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default defineNuxtModule<ModuleOptions>({
defaults: {
enabled: true,
session: {
automaticRefresh: false,
automaticRefresh: true,
expirationCheck: true,
maxAge: 60 * 60 * 24, // 1 day
cookie: {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/server/lib/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export function callbackEventHandler({ onSuccess, onError }: OAuthConfig<UserSes
canRefresh: !!tokens.refreshToken,
loggedInAt: timestamp,
updatedAt: timestamp,
expireAt: accessToken.exp || timestamp + useRuntimeConfig().oidc.session.maxAge!,
provider,
}

Expand Down Expand Up @@ -228,6 +229,10 @@ export function callbackEventHandler({ onSuccess, onError }: OAuthConfig<UserSes
config.optionalClaims.forEach(claim => parsedIdToken[claim] && ((user.claims as Record<string, unknown>)[claim] = (parsedIdToken[claim])))
}

// Expose access token
if (config.exposeAccessToken)
user.accessToken = tokenResponse.access_token

if (tokenResponse.refresh_token) {
const tokenKey = process.env.NUXT_OIDC_TOKEN_KEY as string
const persistentSession: PersistentSession = {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/server/utils/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export async function refreshAccessToken(provider: ProviderKeys, refreshToken: s
const user: UserSession = {
canRefresh: !!tokenResponse.refresh_token,
updatedAt: Math.trunc(Date.now() / 1000), // Use seconds instead of milliseconds to align wih JWT
expireAt: parseJwtToken(tokenResponse.access_token).exp,
}

// Update optional claims
Expand All @@ -77,6 +78,10 @@ export async function refreshAccessToken(provider: ProviderKeys, refreshToken: s
config.optionalClaims.forEach(claim => parsedIdToken[claim] && ((user.claims as Record<string, unknown>)[claim] = (parsedIdToken[claim])))
}

// Expose access token
if (config.exposeAccessToken)
user.accessToken = tokenResponse.access_token

return {
user,
tokens,
Expand Down
1 change: 0 additions & 1 deletion src/runtime/server/utils/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ export async function requireUserSession(event: H3Event) {
})
}
const expired = persistentSession?.exp <= Math.trunc(Date.now() / 1000)
// logger.info(`Session ${sessionId} expires in ${persistentSession.exp - Math.trunc(Date.now() / 1000)} seconds`)
if (expired) {
logger.warn('Session expired')
// Automatic token refresh
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/types/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ export interface OidcProviderConfig {
* @default false
*/
encodeRedirectUri?: boolean
/**
* Expose access token to the client within session object
* @default false
*/
exposeAccessToken?: boolean
}

export interface AuthSession {
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/types/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ export interface UserSession {
canRefresh?: boolean
loggedInAt?: number
updatedAt?: number
expireAt?: number
providerInfo?: any
userName?: string
claims?: Record<string, unknown>
accessToken?: string
}

export interface Tokens {
Expand Down

0 comments on commit 4162eda

Please sign in to comment.