Server utils

Session management

Nuxt session management

Session expiration and refresh

Nuxt OIDC Auth automatically checks if the session is expired and refreshes it if necessary. You can disable this behavior by setting expirationCheck and automaticRefresh to false in the session configuration. The session is automatically refreshed when the session object is accessed. You can also manually refresh the session using refresh from useOidcAuth on the client or on the server side by calling refreshUserSession(event).

Session expiration and refresh is handled completely server side, the exposed properties in the user session are automatically updated. You can theoretically register a hook that overwrites session fields like loggedInAt, but this is not recommended and will be overwritten with each refresh.

With expirationThreshold, the refresh starts before the access token expires. When the provider does not answer such an early refresh, getUserSession returns the current session until its access token expires. The client refresh asks for new tokens explicitly, so it rejects with the 503 even while the access token is valid, and keeps its session state.

Requests to the provider time out after requestTimeout, 10 seconds by default, including the response body. After a refresh request times out, the server process makes no refresh requests to that provider for 30 seconds. During that pause, unexpired sessions keep working and expired ones get the 503 right away.

Using the session in server side code

You can access the user session in your server side code by using the getUserSession function from nuxt-oidc-auth.

import { getUserSession } from 'nuxt-oidc-auth/runtime/server/utils/session.js'

export default eventHandler(async (event) => {
  const session = await getUserSession(event)
  return session.userName
})

nuxt-oidc-auth/runtime/server/utils/session.js is the only runtime module the package exports. Other runtime files are internal and cannot be imported.

By default, getUserSession and refreshUserSession throw an HTTP 401 when the session is invalid or expired and cannot be refreshed.

When the provider does not answer a refresh, both keep the session and throw an HTTP 503 instead, also with errorBehavior: 'redirect'. A refresh counts as unanswered when its token or discovery request gets no response, for example after a network error, or an HTTP 408, 429 or 5xx response. The next refresh tries again with the same refresh token. Any other failure, such as an invalid_grant response, clears the session. On the client, refresh from useOidcAuth rejects with the 503 and keeps its session state.

For API/XHR handlers, you can explicitly choose error behavior:

import { getUserSession } from 'nuxt-oidc-auth/runtime/server/utils/session.js'

export default eventHandler(async (event) => {
  const session = await getUserSession(event, { errorBehavior: 'throw' })
  return { user: session.userName }
})

Use { errorBehavior: 'redirect' } when you want legacy redirect behavior instead of an HTTP error.

Be careful to not expose any sensitive information from the handler code.

Calling APIs with the access token

Use getAccessToken in a server handler to call an API on behalf of the signed-in user. It reads the access token from the encrypted server side token store, so it works with exposeAccessToken: false and the token never has to reach the browser.

The token store has an entry when the provider returns a refresh token, or when exposeAccessToken or exposeIdToken is enabled. For providers without refresh tokens that keep both exposure flags disabled, enable storeAccessToken so the access token is stored for server side use only:

nuxt.config.ts
export default defineNuxtConfig({
  oidc: {
    providers: {
      oidc: {
        storeAccessToken: true,
      },
    },
  },
})

Every stored token is encrypted with NUXT_OIDC_TOKEN_KEY. Set the same key on all server instances and use a storage driver for the oidc storage that all instances share, otherwise a request that lands on another instance or follows a restart can't read the token. See security for the secrets. Logout removes the token record; browser session expiry alone does not remove it.

server/api/orders.get.ts
import { getAccessToken } from 'nuxt-oidc-auth/runtime/server/utils/session.js'

export default eventHandler(async (event) => {
  const accessToken = await getAccessToken(event)
  return await $fetch('https://api.example.com/orders', {
    headers: { Authorization: `Bearer ${accessToken}` },
  })
})

getAccessToken returns a promise for the raw token string. It validates the session the same way as getUserSession. With expirationCheck and automaticRefresh enabled and a refresh token available, it refreshes an expiring token before returning it. The stored token expires at its exp claim. For opaque tokens it expires expires_in seconds after sign-in, and if the provider sends neither, after the session maxAge.

It throws an HTTP 401 when:

  • the session is invalid, or expired and can't be refreshed
  • the session has no stored access token, for example because the provider issued no refresh token and storeAccessToken is disabled. Sessions created by an earlier version without a refresh token also require the user to sign in again
  • the stored access token has expired or has no expiry after any permitted refresh attempt
  • the stored access token can't be decrypted, for example after NUXT_OIDC_TOKEN_KEY changed

It throws an HTTP 503 and keeps the session when the provider does not answer the refresh.

Only return data from the API response. Never return the token itself from your handler.