← Back to blog

Building Trust Surfaces for AI Agents: What Token Vault Taught Us About Authorization at the Speed of Autonomy

5 min read

Bonus Blog Post Submission Authorized to Act: Auth0 for AI Agents

The Problem We Started With

Commerce operations involve real money. When AI agents can modify pricing, toggle promotions, create products, and send notifications on behalf of users, the authorization model cannot be an afterthought. We built Commerce Changeset to test what happens when you take multi-agent orchestration seriously and wire every action through a real identity layer.

The system has four agents: a Reader that pulls product data from Google Sheets, an Orchestrator that decomposes natural language into discrete operations, a Writer that executes approved changes, and a Notifier that sends email receipts via Gmail. Every agent acts on behalf of the authenticated user through Auth0 Token Vault's On-Behalf-Of delegation. The user never hands credentials to an agent directly.

What Token Vault Actually Does (And What Tripped Us Up)

Token Vault's OBO model is elegant: Auth0 stores the user's Google refresh token, and agents exchange it for scoped access tokens at execution time. The user connects their Google account once via Connected Accounts, and every downstream agent gets exactly the permissions it needs without ever seeing the underlying credential.

But the implementation had sharp edges. Here is what we found:

Discovery 1: The async context trap.Token Vault tool execution must happen inside the Vercel AI SDK's tool wrapper async context. Calling getAccessTokenFromTokenVault() outside the withTokenVault() callback throws a generic “No AI context found” error with no indication that the fix is wrapping execution inside the SDK's tool context. The error message does not reference Token Vault, withTokenVault, or the async context requirement — you have to read the SDK source to connect the dots. This cost us two days. The fix was adding setAIContext() at the route level and ensuring all Token Vault calls stay inside the withTokenVault callback chain.

Discovery 2: CIBA binding message restrictions. Binding messages sent to Guardian push notifications are restricted to 64 characters of alphanumeric text plus basic punctuation (whitespace, +, -, _, ., commas, colons, #). No dollar signs, no unicode arrows, no emoji. We built a sanitizer to strip forbidden characters from dynamic changeset descriptions. This restriction is not documented in the SDK reference — you discover it at runtime when Auth0 rejects the request.

Discovery 3: Connected Accounts requires your own Google OAuth credentials. Auth0's dev keys on the google-oauth2 connection do not support Token Vault. You need to register your own Google OAuth app and configure the connection with those credentials before Token Vault will work. This is a setup sequence dependency that is easy to miss.

Discovery 4: Rich Authorization Requests need an enterprise plan. We stubbed the path for CIBA authorizationDetails and built the data structures for per-operation authorization, but the Management API rejects authorization_details on client grants without enterprise licensing. We built the types and plumbing anyway — the enforcement layer is ready when the plan tier allows it.

Discovery 5: Per-agent scope isolation is achievable today. Reader gets spreadsheets.readonly, Writer gets spreadsheets (it needs read access for SKU lookup alongside write access for mutations), and Notifier gets gmail.send. Token Vault enforces the principle of least privilege at the token exchange layer — each agent receives exactly the permissions its role requires, and no more.

Stress-Aware Authorization: A Pattern That Does Not Exist Yet

This is the novel contribution. Our system escalates risk tiers when voice signals indicate the user is stressed or fatigued. A single-record price change that would normally classify as Tier 2 (WRITE) gets reclassified to Tier 3 (BULK) if the user's stress level exceeds 0.7 or the session has run longer than 60 minutes. The policy engine (json-rules-engine) evaluates these signals alongside traditional factors like affected record count and price change percentage.

An important caveat: in the current implementation, the escalation changes the risk classification and UI indicators (amber to red risk badge, different policy explanation), but the underlying approval mechanism is identical — both Tier 2 and Tier 3 trigger the same CIBA Guardian push notification. Differentiating the actual approval experience is the next step. Tier 3 could require a confirmation phrase, a shorter approval timeout, dual-approver workflows, or a mandatory cool-down period before resubmission. The policy engine can already distinguish these tiers — the enforcement layer needs to catch up.

Why this matters: current agent authorization is binary. The agent either has permission or it does not. But human judgment degrades under stress. An authorization system that adapts its approval thresholds and friction based on the user's cognitive state is a meaningful evolution of the consent model, even if our implementation is a first step.

Authorization as Cognitive Protection

This feature is not surveillance. The analogy is a seatbelt warning light: the system notices strain and adds a speed bump, not a roadblock. Stress and fatigue signals are opt-in, assistive, and escalation-only — they feed into the same CIBA confirmation flow the user already knows. The user still approves via push notification. When no voice context exists, the policy engine evaluates the operation exactly as it would without the voice interface, with zero behavioral penalty.

Privacy is non-negotiable here. Voice-derived signals are ephemeral session metadata. No recordings are stored, no biometric profiles are built, and no data leaves the session. The user can disable voice-aware escalation at any time without affecting their base permissions — the system degrades gracefully to standard tier classification. Trust surfaces only work if users trust the surface itself.

What We Would Build Next

  • Differentiated Tier 3 approval: Confirmation phrases, shorter timeouts, or dual-approver flows to make escalation meaningful beyond a UI badge change.
  • Continuous trust scoring: Real-time modulation of agent autonomy rather than binary approve/deny decisions.
  • Ambient trust visualization: Active delegations and token exchange status shown inline in the agent workflow, not in a separate settings page.
  • Context boundary enforcement: The orchestrator can see everything, but the writer should only see the approved operations. Enforcing information boundaries between agents in the delegation chain.

For the Auth0 Team

Direct feedback, framed constructively:

  • The Token Vault + AI SDK async context requirement should be documented with a clear “wrong way / right way” code example. The “No AI context found” error needs to reference the withTokenVault() wrapper and setAIContext() as the solution path.
  • CIBA binding message character restrictions should be documented in the SDK reference, not discovered at runtime via rejected requests.
  • An Auth0 development-tier RAR option would let hackathon participants and early adopters demo fine-grained per-operation authorization without enterprise licensing.
  • Consider a “dry run” mode for Token Vault that validates the OAuth flow without actually exchanging tokens — useful for testing and CI pipelines.