Skip to main content
Dark green background, "Weak Application Security Can Cost You Millions," 3 slanted images of fingers pointing to digital locks, and a "Learn the Basics" button
Token Exchange in Production: A Telco Chatbot Case StudyOAuth & OIDC
5 min readFor Identity Governance Administrators

Token Exchange in Production: A Telco Chatbot Case Study

The Challenge

A customer-support chatbot needs to access payment history and account details from multiple backend services. The user initiates the conversation, but an AI agent decides which tools to use, when to call them, and how to assemble the response. This creates an identity problem: if every downstream API only sees "the agent service called me," the audit trail is lost. You can't determine who authorized the payment lookup, which user's data was accessed, or why the agent chose that tool.

The team faced three constraints:

  1. Audit Gaps: Logs showed service-to-service calls but not which user triggered the agent or which tool the agent selected.
  2. Overprivileged Tokens: Reusing the browser access token across all backend hops meant a bearer credential traveled beyond its intended audience.
  3. Generic Service Accounts: Using one service account for the agent collapsed all user context into "the agent did it."

The requirement was clear: maintain both user identity and workload identity across every hop, without spreading credentials or losing delegation context.

The Environment and Constraints

The architecture included:

  • A browser single-page application (SPA) that signs users in with PingFederate using Authorization Code Flow with Proof Key for Code Exchange.
  • A portal API that receives browser requests and routes them to the agent.
  • An agent service that selects tools and calls an MCP (Model Context Protocol) server.
  • An MCP server that enforces scopes before returning customer profile or payment data.
  • SPIRE deployed in Kubernetes to issue workload credentials.

Each service ran in its own namespace with its own service account. The team needed to prove which workload was making each request without shared secrets or long-lived API keys.

The Approach Taken

The solution combined OAuth 2.0 Token Exchange (RFC 8693) with SPIFFE/SPIRE for workload identity.

Token Exchange Model: At each service boundary, the calling service requests a new access token from PingFederate. The request includes:

  • A subject_token representing the user (the incoming OAuth access token).
  • An actor_token representing the workload (a SPIFFE JWT-SVID from SPIRE).
  • A requested_token_type of urn:ietf:params:oauth:token-type:access_token.
  • A target audience for the next service.

PingFederate validates both tokens and mints a new access token scoped to the next hop. The user remains the subject in every token. The actor changes at each hop to reflect which workload is making the request.

Workload Identity: SPIRE issues JWT-SVIDs (SPIFFE Verifiable Identity Documents) to each Kubernetes workload based on platform attestation. The portal gets a JWT-SVID with subject spiffe://ping.demo/ns/spiffe-token-exchange-demo/sa/portal. The agent gets one with subject spiffe://ping.demo/ns/spiffe-token-exchange-demo/sa/agent.

These JWT-SVIDs are short-lived workload credentials. The portal and agent fetch them from the SPIFFE Workload API before calling PingFederate. No shared secret is needed between the workload and PingFederate. Trust is based on validating the JWT-SVID issuer, signature, audience, and SPIFFE subject.

Flow: When the browser calls the portal API with a user token, the portal:

  1. Validates the user token.
  2. Fetches a portal JWT-SVID from SPIRE.
  3. Sends a token exchange request to PingFederate with the user token as subject and the portal JWT-SVID as actor.
  4. Receives an agent token with audience Agent and actor claim Portal API.
  5. Calls the agent with the agent token.

When the agent needs to call the MCP server, it repeats the pattern: fetch an agent JWT-SVID, exchange the agent token for an MCP token, call the MCP server with the MCP token.

Each token is minted for a specific audience. The MCP server validates that the token it receives was issued for MCP Server, not for Agent or Portal API.

Results and Metrics

The implementation delivered three measurable improvements:

Audit Trail: Every token now carries both user identity (in the sub claim) and workload identity (in the act claim). Logs at the MCP server show which user initiated the request, which agent processed it, and which portal forwarded it.

Scoped Tokens: Each service receives a token minted for its own audience. The portal can't use its token to call the MCP server directly. The agent can't reuse the portal's token. PingFederate enforces that the portal workload can only request tokens for the agent audience, and the agent workload can only request tokens for the MCP audience.

No Shared Secrets: Workload authentication is based on SPIFFE attestation, not static credentials. The team doesn't manage API keys or client secrets for the portal and agent services.

What They Would Do Differently

The team identified two gaps:

Policy Enforcement: PingFederate validates the actor JWT-SVID signature and audience, but it doesn't enforce which scopes each workload can request. The portal could theoretically ask for the full scope set even if it only needs a subset. The next iteration will add scope-mapping rules in PingFederate to restrict which scopes each actor SPIFFE ID can request.

Token Lifetime Coordination: The JWT-SVIDs expire independently from the OAuth access tokens. If a JWT-SVID expires mid-session, the workload must fetch a new one before the next token exchange. The team is considering a token-refresh wrapper that checks expiration before each exchange to avoid runtime errors.

Takeaways for Your Team

If you're building agent-based workflows, this pattern solves three problems:

  1. Delegation Without Credential Spread: You don't reuse the user's browser token across backend services. Each service gets a token minted for its audience.
  2. Workload Proof Without Shared Secrets: SPIFFE JWT-SVIDs give you attested workload identity. PingFederate validates the JWT-SVID issuer and signature instead of checking a static client secret.
  3. Audit Context Across Hops: The act claim in each token shows which workload made the request. You can reconstruct the full chain without stitching together disconnected logs.

The implementation requires:

  • An OAuth 2.0 authorization server that supports RFC 8693 token exchange (PingFederate does; check your vendor's documentation).
  • A SPIFFE implementation like SPIRE that can issue JWT-SVIDs to your workloads.
  • Workload code that fetches JWT-SVIDs from the SPIFFE Workload API and includes them as actor tokens in token exchange requests.

If your current architecture uses one service account for all backend calls, you're losing user context. If you're passing the browser access token to every backend service, you're spreading a bearer credential beyond its intended audience. Token exchange with workload identity gives you a third option: mint a new, scoped token at each boundary, with both user and actor identity in the chain.

Promotional banner for the Penetration Report Template Kit

You Might Also Like