Toby Allen

Auth0 Session and Token Management: Every Option Explained

· Auth0, Customer Identity Products, Identity Security

Auth0 gives you a lot of knobs to turn when it comes to sessions and tokens. There are three different session layers, four distinct refresh token variants (with a fifth in beta), two approaches to user self-service, server-to-server logout, admin-level session revocation, and a set of Actions APIs that let you dynamically override all of the above at runtime. That's before you add sender-constraining into the mix.

If you've ever stared at the Auth0 dashboard wondering which combination of settings is actually right for your application — and why the answer always seems to be "it depends" — this post is for you. In this post I will map out every option, explain what each one does, and show how they work together for different application types.

The areas we cover are as follows.

  1. The three session layers
  2. The refresh token spectrum: Rotation, Online, Multi-Resource, and Metadata
  3. DPoP — binding tokens to the client
  4. Logout and revocation: from simple redirect to back-channel notification
  5. Admin session control via the Session Management API
  6. User self-service: My Account API and Universal Components
  7. Dynamic session logic with Actions
  8. How these options stack for different application types

The Three Session Layers

Everything in Auth0 session management starts with understanding that there is not one session — there are three independent layers, and they do not automatically synchronise.

The application session is managed entirely on your side. It is whatever mechanism your application uses to track whether a user is logged in: a cookie, a server-side cache entry, a JWT stored in memory. Auth0 has no visibility into this layer and cannot terminate it directly.

The Auth0 session (also called the SSO session) lives inside Auth0's own infrastructure, maintained as a browser cookie on your Auth0 domain. This is what enables single sign-on across multiple applications. If a user has an active Auth0 session and visits a second application that trusts the same Auth0 tenant, they are authenticated automatically without being prompted to log in again.

The federated IdP session exists when a user authenticated through an external identity provider — Google, Microsoft Entra, an enterprise SAML IdP. That provider maintains its own session independently of Auth0. Even if you terminate both the application session and the Auth0 session, the user may re-authenticate silently via the IdP without being prompted for credentials.

Application Session Managed by your app — server cookie, in-memory state, or local cache Auth0 has no visibility into this layer Cleared by: Your own logout code Auth0 SSO Session Browser cookie on your Auth0 domain — enables single sign-on across apps Shared across all applications on the same tenant Cleared by: /v2/logout redirect Federated IdP Session Google, Microsoft, or enterprise SAML / OIDC provider Auth0 has no control — user may re-auth silently via the IdP Cleared by: IdP-specific logout Clearing layer 1 does not clear layer 2. Users can be silently re-authenticated even after your app logs them out.
Figure 1 — The three session layers and what is required to clear each one

The practical consequence of this architecture is that "logging a user out" is more complex than it looks. Clearing your application's session cookie removes access to your app, but leaves the Auth0 SSO session intact, meaning the user will be silently re-authenticated on their next visit. Redirecting to the Auth0 /v2/logout endpoint clears the Auth0 session — but does not (by default) notify your other applications that the session ended. And none of this touches the IdP layer.

Auth0 provides configuration controls for session lifetime limits — both an idle timeout (reset on activity) and an absolute maximum — that govern how long the Auth0 session can remain active. Understanding these three layers is the prerequisite for everything else in this post.


The Refresh Token Spectrum

Refresh tokens are long-lived credentials that allow an application to obtain a new access token without requiring the user to log in again. Auth0 offers four distinct variants, each suited to different scenarios. They are not all interchangeable — most notably, online_access (ORTs) and offline_access (standard refresh tokens) cannot be requested in the same flow.

Standard Refresh Tokens with Rotation

The baseline. When a user logs in and your application requests offline_access, Auth0 issues a refresh token that is independent of the Auth0 session. The token persists even after the SSO session ends and is stored on the application side (server-side for web apps; the iOS Keychain or Android Keystore for native apps).

The key security control is Refresh Token Rotation. With rotation enabled, every time the application exchanges a refresh token to get a new access token, Auth0 simultaneously issues a brand-new refresh token and invalidates the old one. Critically, if an already-invalidated token is submitted — which would happen if an attacker had stolen it and used it after the legitimate client already had — Auth0 revokes the entire token family and both parties are forced to re-authenticate. This detection mechanism is what makes refresh tokens reasonably safe for long-lived sessions.

When to use it: native mobile apps (where the Keychain/Keystore provides secure storage), server-side web applications, or any scenario where you need session continuity beyond the Auth0 SSO session lifetime. You configure expiry via Configure Refresh Token Expiration.

Standard Refresh Token
Session bindingNone — independent of Auth0 session
LifetimeConfigured idle + absolute limits
RotationYes, with automatic reuse detection
Visible in Management APIYes
Can be revoked individuallyYes
Your App Auth0 Attacker Normal exchange Exchange RT₁ AT + RT₂ issued • RT₁ retired Attacker submits stolen RT₁ (already retired) Exchange RT₁ ⚠ Reuse detected Entire token family revoked RT₂ revoked RT₁ rejected ⚠ Must re-authenticate ⚠ Access denied Both the legitimate session and the attacker are invalidated — this is intentional. Neither can proceed without re-authenticating, which forces the user to notice that something unusual has occurred.
Figure 2 — Refresh token rotation: normal exchange and automatic reuse detection

Online Refresh Tokens (ORTs) — Beta

Online Refresh Tokens are designed specifically for browser-based single-page applications, and they exist to solve a concrete problem: Apple's Intelligent Tracking Prevention (ITP) and equivalent mechanisms in Firefox and Brave block third-party cookies by default. Traditional silent authentication in SPAs relies on an invisible iframe querying Auth0's /authorize endpoint — which depends on third-party cookies that these browsers increasingly refuse to set. SPAs started breaking for Apple users silently.

ORTs solve this by replacing iframe-based silent auth with an actual token exchange. Instead of requesting offline_access, the SPA requests online_access. Auth0 issues a refresh token that is cryptographically bound to the user's active Auth0 session cookie. Each time the SPA uses the ORT to refresh its access token, Auth0 resets the session's idle timeout — keeping the user logged in as long as they remain active. When the Auth0 session ends (whether by explicit logout, absolute timeout, or administrative revocation), the ORT is immediately invalidated.

This tight coupling is the ORT's defining characteristic. You cannot have an ORT outlive its session, which is exactly what you want in a browser context where a refresh token stored in memory or IndexedDB could otherwise persist independently.

There are important constraints to know. ORTs cannot be combined with offline_access in a single request. They are not visible through the Management API and cannot be individually revoked — revocation happens by terminating the underlying session. And for public clients (SPAs), DPoP is mandatory when using ORTs — the Online Refresh Token documentation lists this as a hard requirement. The feature is currently in beta.

Online Refresh Token
Session bindingBound to active Auth0 session
LifetimeFollows session idle/absolute limits
RotationNo — token string is reused
Visible in Management APINo
Can be revoked individuallyNo — revoke via session deletion
DPoP required (public clients)Yes

Multi-Resource Refresh Tokens (MRRTs)

A common pattern in modern application architecture is that a single user-facing application needs to call multiple backend APIs — a billing service, an inventory service, a notifications service — each registered as a separate resource server (audience) in Auth0. The traditional approach required separate authorisation flows for each audience, which either forces multiple browser redirects at login or requires up-front requesting of all audiences simultaneously (which hits consent scope and rate limits).

Multi-Resource Refresh Tokens allow a single refresh token to obtain access tokens for multiple APIs, each scoped to its own audience and permissions. The client configures a refresh_token.policies array on its application record via the Management API, listing the permitted audiences and scopes. When exchanging the MRRT, the client specifies which audience it needs — Auth0 validates the request against the policy and returns an access token scoped to that specific API, without any browser redirect.

Each access token issued through an MRRT exchange is still scoped to a single API. MRRTs are available to first-party applications only, and the Auth0 Management API itself cannot be included in the policy list.

Multi-Resource Refresh Token
Use caseOne token, access to multiple APIs
RequiresFirst-party app, Management API policy config
Per-exchange outputSingle access token for one audience
Auth0 Management API as audienceNot supported

Refresh Token Metadata

Refresh Token Metadata is a newer addition that allows you to store custom key-value pairs directly on a refresh token at the moment it is issued. The metadata is set via Post-Login Actions and follows the token for its lifetime.

The practical uses are broader than they first appear. You can stamp the token with device context (browser, OS, approximate location) at issuance, then read that metadata back in a subsequent token exchange Action to drive conditional logic — for example, triggering step-up MFA if the device context has changed, or surfacing "Session from Chrome on macOS" labels in a user-facing session management dashboard. You can also use metadata to share state across multiple Actions in a single flow without needing an external data store.

Key limits: up to 25 entries per token, keys and values capped at 255 characters. Metadata can only be written at issuance; reading existing values via event.refresh_token.metadata is available during subsequent token exchanges, not during the initial login flow before the token exists.


DPoP — Sender Constraining

All of the token types above are bearer tokens by default. A bearer token is essentially a password: whoever possesses it can use it, regardless of whether they are the legitimate client. If an attacker extracts a bearer access token from a compromised SPA — via XSS, a browser extension, a logging system that shouldn't be there — that token is immediately usable against your APIs.

Demonstrating Proof-of-Possession (DPoP) solves this by binding access tokens cryptographically to the client that requested them. The client generates a public/private key pair (using the browser's Web Crypto API, in the case of a SPA — the private key lives in IndexedDB and cannot be extracted by JavaScript). On every token request and every API call, the client signs a DPoP Proof JWT containing the target HTTP method, the target URL, a unique identifier, and a timestamp. Auth0 validates the signature and issues an access token whose cnf (confirmation) claim encodes the client's public key. Any downstream API that validates DPoP will reject requests that arrive without a matching, freshly-signed proof — so a stolen token without the private key is worthless.

The auth0-spa-js SDK handles DPoP proof generation, nonce management, and automatic retry on nonce errors transparently. Enabling it on the client is a single configuration flag (useDpop: true). The Auth0 application settings include a "Require Token Sender-Constraining" toggle that enforces DPoP at the tenant level for that application.

DPoP is mandatory for public clients (SPAs and native apps) using Online Refresh Tokens, and strongly recommended for any public client that stores tokens in the browser.

Auth0 binds the access token to the client's public key (cnf claim). Every API call must include a DPoP Proof signed with the matching private key. Legitimate client Attacker (stolen AT, no private key) Client AT + private key (IndexedDB) Resource API validates DPoP proof AT + DPoP proof 200 OK ✓ Attacker AT only — no key to sign a proof Resource API no valid proof AT only 401 — DPoP required ✗ The private key is generated by the browser's Web Crypto API and stored in IndexedDB — it cannot be read by JavaScript. Stealing the access token is not enough. Without the private key, the DPoP proof cannot be generated and the API rejects the request.
Figure 3 — DPoP sender-constraining: why a stolen access token is unusable without the bound private key

Logout and Revocation

Terminating a session in Auth0 has several mechanisms with different scopes of effect.

Standard Logout

The simplest approach: redirect the user's browser to https://{yourDomain}/v2/logout. This clears the Auth0 SSO session cookie. If returnTo is configured, the user is sent back to your application after the session is cleared. This does not touch other applications that shared the SSO session, and it does not revoke any refresh tokens the application may have stored.

Back-Channel Logout

Back-Channel Logout implements the OIDC Back-Channel Logout 1.0 specification and is available on Enterprise plans. When a user's Auth0 session ends — whether through explicit logout, administrative deletion via the Session Management API, or a trigger from Okta's Universal Logout — Auth0 sends a signed Logout Token directly to a registered backchannel_logout_uri endpoint on each affected application. The application validates the JWT, extracts the sid claim, and terminates its own server-side session.

This is the mechanism that makes true federated logout possible. Without it, each application is entirely unaware that the SSO session ended and will simply continue serving the user until its own session expires or the user returns and gets re-authenticated. With back-channel logout, the application can immediately invalidate cached sessions, force redirects to login on the next request, and participate in coordinated incident response when an account is compromised.

The tradeoff: back-channel logout is server-to-server only (the application must have a reachable HTTPS endpoint), it is asynchronous (Auth0 queues the notification, so there is a small delay), and SPA clients that do not have server-side session state need a different approach.

Session terminated at Auth0 via /v2/logout, Management API DELETE, or Okta Universal Logout Auth0 queues Logout Tokens for registered apps POST Logout Token POST Logout Token POST Logout Token Application A /backchannel-logout Application B /backchannel-logout Application C /backchannel-logout session invalidated session invalidated session invalidated Server-to-server — fires even if the user's browser is closed. Each app validates the Logout Token JWT, extracts the sid claim, and destroys the matching server-side session. Requires Enterprise plan and a registered HTTPS endpoint.
Figure 4 — Back-channel logout: Auth0 notifies every registered application when a session ends

Session Management API

The Session Management API provides programmatic, out-of-band access to the active sessions within the Auth0 layer. This is an Enterprise plan feature. Via the Management API you can retrieve all sessions for a user (with device, IP, and authentication-time metadata), fetch or delete a specific session by ID, and wipe all sessions for a user in a single call.

Deleting a session via the Management API triggers back-channel logout for any applications that have registered a backchannel_logout_uri. This makes it the correct mechanism for building an admin "kill this user's access everywhere" workflow or a user-facing "revoke this device" session management dashboard.

Operations are eventually consistent — deletion is asynchronous, not instant.


User Self-Service: My Account API and Universal Components

Auth0 provides two overlapping but distinct options for letting users manage their own credentials and enrolled factors.

My Account API

The My Account API is a client-facing REST API, scoped to the currently logged-in user via https://{yourDomain}/me/ as the audience. It allows users to enrol, list, update, and delete their own authentication factors — TOTP, email OTP, SMS OTP, passkeys, push notifications, and recovery codes. It also supports linking and unlinking connected accounts (where Token Vault scopes are configured).

The security design is worth understanding. Machine-to-machine access is blocked by design; only tokens held by an actual end user can call it. The application must explicitly request user-delegated scopes (create:me:authentication_methods, read:me:authentication_methods, and so on) and have those scopes granted on the Auth0 application's Application Access tab. An optional "Default Policy" setting enforces step-up MFA within 15-minute windows for write operations, meaning a user's active session must include a fresh MFA challenge before they can enrol or remove a factor.

This API is what you would call directly if you want to build a fully custom self-service security UI — complete control over the UI, calling Auth0 endpoints server-side or directly from the browser.

Universal Components

Universal Components are pre-built UI component libraries that sit on top of the My Account API (for iOS and Android self-service) and the My Organization API (for web-based delegated administration). Rather than calling Auth0 endpoints directly and building your own UI, you embed a component that handles the interaction pattern for you.

The web component (React, Next.js, with a shadcn variant) covers creating and managing Auth0 Organizations — useful for B2B SaaS applications where you want to give your business customers a self-service panel to manage their own SSO connections, user roles, and branding without you building a custom admin portal. The iOS (SwiftUI) and Android (Jetpack Compose) components expose the My Account API features — factor enrolment, passkey management, recovery codes — as native-looking UI that you embed in your mobile app.

Universal Components are currently in beta. The tradeoff versus calling the APIs directly is speed of implementation against flexibility: the components cover the common flows well, but if your UI requirements deviate significantly, you will end up wrapping or forking them.


Dynamic Session Logic with Actions

Auth0 Actions give you a JavaScript runtime that executes at defined points in authentication flows, and the session management APIs exposed to Actions are more powerful than they might initially appear.

Within a Post-Login Action, event.session surfaces the current session's metadata: unique ID, creation timestamp, authentication time, device details including IP address, ASN, and User-Agent. Combined with event.authentication (which methods were used) and event.request (the current request context), this gives you the inputs to make real-time policy decisions.

api.session.revoke() terminates the current session from inside the Action, denies the current transaction, revokes associated refresh tokens (optionally), and triggers back-channel logout across all bound applications. The canonical use case is mid-session risk detection: if the ASN on the current request differs from the ASN recorded when the session was first established, revoke immediately rather than waiting for a token to expire.

api.session.setExpiresAt() and api.session.setIdleExpiresAt() allow per-user or per-organisation session lifetime overrides, within the bounds of the tenant-level maximums. You might give employees in a high-risk role a 2-hour absolute limit while giving regular users the full 24 hours.

api.session.setCookieMode() switches between persistent sessions (normal) and non-persistent, memory-only sessions. The intended use case is shared or public devices — if the user indicates they are on a shared computer, the session disappears when the browser closes.


How These Options Stack

The right combination depends on the application type. The table below gives a starting point for each pattern.

Application TypeAuth FlowRefresh TokenToken BindingLogoutSession Admin
Traditional server-side web appAuth Code + PKCEStandard with RotationNot requiredBack-Channel LogoutSession Management API
Single-Page Application (basic)Auth Code + PKCEStandard with RotationDPoP (recommended)Front-channel redirect
Single-Page Application (hardened)Auth Code + PKCEOnline RT (Beta)DPoP (required)Session deletionSession Management API
Backend-for-Frontend (BFF)Auth Code + PKCE (server-side)Standard with RotationNot required (server)Back-Channel LogoutSession Management API
Native mobileAuth Code + PKCEStandard with RotationDPoP (optional)Local token deletionSession Management API
Multi-API applicationAuth Code + PKCEMulti-Resource RTDPoPBack-Channel LogoutSession Management API
Enterprise with risk controlsAnyAnyDPoPBack-Channel LogoutSession Management API + Actions

A few combinations worth calling out.

BFF + back-channel logout + Session Management API is the pattern to reach for when you have strict security requirements. Tokens never touch the browser (the BFF holds them server-side), back-channel logout ensures propagation when any session ends, and the Session Management API gives you (or the user) the ability to revoke specific sessions by device. Adding Refresh Token Metadata lets you label each session with device context in the UI.

SPA + DPoP + Online Refresh Tokens is the emerging modern pattern for pure browser apps. ORTs replace iframe-based silent auth (which is dying on ITP-enabled browsers), DPoP ensures that even if a token escapes the browser its value is zero without the bound private key, and the session-binding means revocation is synchronised with the Auth0 session rather than managed independently.

Actions + Session Management API + risk signals is what takes you from static timeout-based expiry to adaptive, behavioural session management. An Action inspects the session context on every authentication, revokes on anomaly, and the Management API gives an admin dashboard the ability to terminate sessions in response to external threat intelligence.


Conclusion

The breadth of Auth0's session and token options reflects the genuine complexity of modern identity. Different application types have genuinely different threat profiles, and a token design that is appropriate for a native mobile app running on a device with a hardware-backed Keychain is not appropriate for a SPA where any malicious script can reach into the same memory space.

The options here are not competitors — most production applications will use several of them together. The key is understanding which layer each one operates at, what its lifecycle and revocation semantics are, and what the tradeoff is between security, user experience, and implementation complexity.

Subsequent posts in this series will walk through implementing each of these patterns end-to-end, starting with the traditional server-side web application and moving through to the SPA and BFF patterns. If you want to see all of these options demonstrated together in a single deployed application, that is also in progress.

For further reading on the individual capabilities, the official Auth0 documentation is the right starting point: