Skip to content

Token Vault

Auth0 feature for persisting and managing upstream refresh tokens on behalf of users, so agents can call third-party APIs (Slack, Google, Facebook, etc.) without re-authenticating the user each session.

What it solves

The naive pattern — "just pass the user's access token to the agent" — is an anti-pattern. Tokens expire; the agent will need to re-prompt the user constantly, breaking autonomy. Worse, the agent gets whatever scopes the user's main session has, not a narrow subset.

Token Vault's pattern: once the user connects an upstream provider (Slack, Gmail, etc.) via Auth0, Auth0 stores the refresh token and manages its lifetime. When the agent needs to act, it performs a token exchange — its own agent-client access token → upstream-provider access token with explicitly requested scopes.

The three-way trust triangle

The call is not user → upstream. It's:

  1. User authenticates with agent (ID token + agent-client access token)
  2. User pre-authorizes connections (slack, google-calendar, stock-trade) via Auth0 — once
  3. Agent, acting on behalf of user, exchanges its token for an upstream token with specific scopes
  4. Upstream API sees an access token with scopes = what the user pre-authorized, actor = agent (via azp / authorizing-party claim)

This means: the user grants access once per upstream provider. Next session, the agent just does the exchange — no re-consent dance, no prompt flood.

Flow variants

  • Refresh-token exchange — for traditional web apps / native apps with a backend, Next.js full-stack.
  • Access-token exchange — for single-page apps or environments like LangGraph where there's no secure backend; short-lived access tokens only.
  • Custom API client — for MCP servers needing to access remote data; Auth0 now supports linked clients (API ↔ client relationships).

Scope restriction is enforced

Scopes requested in a token exchange that weren't part of the original connection are silently ignored or rejected. Prompt injection cannot escalate scopes via the token-exchange mechanism — "scopes not part of the connection can never end up in the access token." The authorization happens before the tool executes, in code, not inside the LLM.

Cross-references