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 RFC 8693 token exchange flows for service delegation and external identity bridging, 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. Token exchange flows — On-Behalf-Of and Custom Token Exchange
  5. Logout and revocation: from simple redirect to back-channel notification
  6. Admin session control via the Session Management API
  7. User self-service: My Account API and Universal Components
  8. Dynamic session logic with Actions
  9. 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 client 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.

Legitimate client Client AT + private key (IndexedDB) private key cannot be extracted Resource API validates DPoP proof signature matches cnf claim AT + freshly-signed DPoP Proof (method, URL, nonce) 200 OK Attacker (stolen AT - no private key) Attacker stolen AT only no key to sign a proof Resource API no DPoP proof presented rejects request AT only - cannot construct a valid DPoP Proof without the private key 401 - DPoP proof required Why sender-constraining works The private key is generated by the browser Web Crypto API and stored in IndexedDB - it cannot be read by JavaScript or extracted by XSS. Every DPoP Proof is single-use (nonce) and bound to a specific URL and HTTP method, so a captured proof cannot be replayed. A stolen access token without the matching private key is worthless - the resource server rejects every request without a valid proof. auth0-spa-js handles DPoP proof generation, nonce management, and retry transparently. Enabling it is a single flag: useDpop: true.
Figure 3 - DPoP sender-constraining: why a stolen access token is unusable without the bound private key

Token Exchange Flows — RFC 8693

The options covered so far address the lifecycle of tokens between a user and the applications they directly authenticate with. RFC 8693 - OAuth 2.0 Token Exchange extends this with a different set of problems: what happens when one service needs to act on behalf of a user when calling a second service, or when an application needs to accept an identity credential from a system Auth0 does not natively trust?

Both problems use the same grant type - urn:ietf:params:oauth:grant-type:token-exchange at the token endpoint - but they work differently and serve different use cases. Auth0 currently offers two implementations.

On-Behalf-Of Token Exchange

On-Behalf-Of (OBO) token exchange allows a middle-tier service to present a user's incoming access token to Auth0 and exchange it for a new access token scoped to a different downstream API. The original user's identity is preserved throughout - the sub claim in the issued token still refers to the end user, not the service that performed the exchange.

The auditable aspect of OBO is the act claim. Auth0 appends a delegation chain to the issued token recording every service in the exchange path. A chain of SPA - Middle Tier - Downstream API produces an act structure where the outermost subject is the middle-tier client, with the original calling service nested inside. Any downstream API can inspect this chain to understand both who the user is and which services were involved in the delegation - without any out-of-band communication.

Configuring OBO requires several steps. The middle-tier client must be a Custom API Client in Auth0 - app_type: resource_server with a resource_server_identifier linking it to the resource server it represents. The client must have token_exchange.allow_any_profile_of_type: ["on_behalf_of_token_exchange"] set via the Management API. A user-delegated client grant (subject_type: user) is required between the middle-tier client and the downstream API. Auth0 enforces a maximum delegation depth of 4 nested act levels - a chain beyond this returns a 400 error.

The canonical use case right now is AI agent architectures, where a user authorises an agent and the agent calls downstream APIs on the user's behalf, with a cryptographically auditable delegation trail rather than a forwarded credential.

On-Behalf-Of
DirectionUser AT in, downstream AT out
Identitysub preserved, act records the chain
Use caseMicroservices, AI agents, multi-hop service calls
Client requirementCustom API Client (app_type: resource_server)
Max chain depth4 nested act levels
User App SPA or web app AT1 middle-tier audience Middle Tier Custom API Client Auth0 /oauth/token exchange AT1, audience=orders AT2: sub=user, azp=middle-tier AT2 orders audience Downstream Orders API AT2 claims — user identity preserved, delegation chain auditable "sub": "auth0|user123" original end user unchanged throughout "azp": "middle-tier-client" the service that performed the exchange "act": {"sub": "middle-tier"} delegation chain — each hop appends a nested act level The downstream Orders API verifies both who the user is (sub) and which service acted on their behalf (azp/act) — without any out-of-band communication. Auth0 enforces a maximum chain depth of 4 nested act levels. Exceeding this returns a 400 error.
Figure 4 — On-Behalf-Of exchange: user identity travels end-to-end; the act claim records the delegation path

Custom Token Exchange

Custom Token Exchange (CTE) solves the inverse problem: accepting an identity credential Auth0 does not natively understand and converting it into a full Auth0 session. Where OBO starts from within Auth0 and delegates outward, CTE starts outside Auth0 and bridges inward.

The subject token can be any format - a JWT from a partner IdP, a SAML assertion, an opaque device attestation token, or an arbitrary string. Auth0 itself does not validate the incoming token; that responsibility sits entirely with an Actions trigger bound to a CTE Profile. The Action verifies the signature and claims, maps the external identity to an existing Auth0 user (or provisions a new one using create_if_not_exists), and returns full Auth0 AT, ID token, and optionally a refresh token. No browser redirect. No Universal Login.

A CTE Profile links an Action to a specific subject_token_type URI - a custom URN you define. When Auth0 receives a token exchange request with that type, it fires the bound Action. You can run different Actions for different external token formats on the same tenant, each with its own validation logic.

The security responsibility falls on the implementer. The Auth0 documentation is explicit on this: you must implement strong validation of the token you receive. A CTE Action that accepts tokens without verifying the cryptographic signature is an authentication bypass. For production use, the Action should validate the signature against a JWKS endpoint or a shared key stored in Action secrets, check the issuer, and enforce expiry.

CTE is currently in Early Access and available on B2C Professional, B2B Professional, and Enterprise plans.

Custom Token Exchange
DirectionExternal token in, Auth0 AT + ID token + RT out
Token formatAny format - JWT, SAML, or arbitrary
ValidationDelegated entirely to the bound Action
User provisioningcreate_if_not_exists for first-seen identities
Use caseExternal IdP federation, identity migration, device attestation
Plan requirementB2C/B2B Professional or Enterprise (Early Access)
Partner IdP external identity provider — any token format external JWT Your App server-side — no browser redirect POST /oauth/token grant_type=token-exchange subject_token=external JWT Auth0 + CTE Action validates JWT signature, maps identity setUserById or create_if_not_exists Auth0 User existing user found or new user created AT + ID token + RT No browser redirect. No Universal Login. The exchange is entirely server-side. Auth0 does not validate the subject_token — the CTE Action bears full responsibility. A CTE Action that skips signature verification is an authentication bypass. Verify against a JWKS endpoint or Action secret. Early Access — B2C Professional, B2B Professional, and Enterprise plans.
Figure 5 — Custom Token Exchange: an external token is validated by an Action and exchanged for full Auth0 credentials, with no browser redirect

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 each registered app POST POST POST 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 backchannel_logout_uri on each application.
Figure 6 — 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
AI agent / service meshAuth Code (user-facing app)Standard with RotationDPoPOBO for downstream callsSession Management API
External IdP or identity migration— (CTE is the auth)CTE issues RTStandard logout

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.

A follow-up post walks through implementing all of these patterns end-to-end in a single deployed application - traditional server-side web app, SPA with DPoP, BFF with MRRTs, On-Behalf-Of delegation, and Custom Token Exchange - with a unified session view that shows how they correlate at the Auth0 Authorization Server layer: Building a Live Auth0 Token and Session Demo.

Update (29 July 2026): Two more grant types are worth adding to this taxonomy, both now covered in the demo above: CIBA and the Device Authorization Grant. Both are decoupled from the requesting device's own browser, but they solve different problems - CIBA already knows who the user is and pushes an approval to a device they already own, while Device Authorization Grant knows nothing about the user until a second screen resolves it, and needs no MFA enrolment or Enterprise plan to work. CIBA can also carry Rich Authorization Requests, part of Auth0's Highly Regulated Identity feature set, letting an approval push show structured, itemised transaction data instead of one opaque string. Full write-ups: CIBA with a real Guardian push and the Device Authorization Grant's native client requirement.

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