Identity for AI

Transaction Tokens in the AuthPlayground

Preserving trusted context through a chain of microservices.

Enterprise AI workflows often involve multiple services. Consider a planner agent that needs customer information to complete a task. It asks a retrieval agent to gather the information, and the retrieval agent calls account context and customer intelligence services.

As the request moves through the call chain, each service can usually identify its direct caller. Preserving the trusted context behind the overall transaction is more difficult. Several hops later, a service might know that it was called by the customer intelligence service. The enterprise needs to know:

  • Which transaction does this call belong to?

  • Which principal is associated with the transaction?

  • Which workload originally requested the transaction token?

  • What’s the purpose or authorization scope of this transaction?

  • Is this context valid inside this trust domain?

  • Is the token still current?

Transaction tokens (IETF draft) carry trusted context through the call chain.

The transaction token model

A transaction token is a short-lived, signed JSON Web Token (JWT) associated with a specific transaction and trust domain. It carries information such as:

  • sub: Who or what is the principal of this transaction?

  • txn: Which transaction is this?

  • req_wl: Which workload requested the transaction token?

  • aud: Which trust domain is this token valid in?

  • scope: What’s the purpose or authorization scope?

  • exp: How long is this context valid?

  • iat: When was this token issued?

A simplified example looks like this:

Header {
  "typ": "txntoken+jwt",
  "alg": "RS256",
  "kid": "transaction-token-signing-key"
}

body
{
  "sub": "demo-user@example.com",
  "txn": "txn-48291",
  "req_wl": "meeting-prep-agent.bx.internal",
  "aud": "bx-ai.internal",
  "scope": "customer.meeting-prep",
  "iat": 1786575243,
  "exp": 1786575303
}

Actual claims and values depend on the Transaction Token Service (TTS) and deployment requirements. Downstream workloads receive a cryptographically protected representation of the transaction instead of reconstructing the security context from arbitrary headers.

What’s a trust domain?

A trust domain is a group of systems that share a common set of security controls and policies. For example, an enterprise might operate several AI services inside one governed environment.

The transaction token is valid within that trust domain, which is why the aud claim is important. It doesn’t represent an individual service (such as aud = Account Context Service). Instead, it represents the entire domain (such as aud = AI Trust Domain). Workloads must not accept a transaction token outside the trust domain identified by its aud claim.

A human isn’t required

A transaction token can support a human-initiated workflow, but a human isn’t required. For autonomous workloads, the transaction might originate entirely from software. The principal represented by the transaction could be a workload instead of a person.

Consider an autonomous monitoring agent versus a human-initiated meeting preparation request. In the human-initiated request, Sarah is the principal. Transaction tokens preserve trusted authorization and request context through a call chain inside a trust domain for both patterns.

The AuthPlayground implementation

Entities involved: Client application, transaction token service, resource server

The AuthPlayground demonstrates the Transaction Token flow in three steps:

  1. Obtain the subject token.

  2. Request the transaction token.

  3. Propagate the transaction token.

Step 1: Obtain the subject token

The calling workload obtains an OAuth access token from the authorization server:

POST /idp/token
Content-Type: application/x-www-form-urlencoded

{
  "grant_type": "authorization_code",
  "code": "<authorization_code>",
  "redirect_uri": "<callback>",
  "client_id": "playground-demo-client",
  "code_verifier": "<pkce_verifier>"
}

The response contains an access token:

{
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile email",
  "access_token": "<access_token>",
  "id_token": "<id_token>"
}

The OAuth access token becomes the subject_token used when requesting the transaction token. It establishes the subject context from which the TTS can create transaction-scoped context.

The transaction token specification is broader than this example. A Txn-Token can represent externally or internally originated transactions. An OAuth user access token isn’t required for every possible transaction token use case.

Step 2: Request the transaction token

The calling workload requests a transaction token from the TTS:

POST /tts/token
Content-Type: application/x-www-form-urlencoded

{
  "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
  "subject_token": "<subject_token>",
  "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "requested_token_type": "urn:ietf:params:oauth:token-type:txn_token",
  "audience": "example.org",
  "scope": "read write",
  "request_context": "{\"req_ip\":\"203.0.113.42\",\"authn\":\"urn:mace:incommon:iap:silver\"}",
  "request_details": "{\"action\":\"read\",\"resource\":\"/api/data\"}"
}

Notice the following details:

  • subject_token: Provides the subject context for the transaction.

  • requested_token_type: Explicitly asks for a transaction token.

  • audience: Identifies the trust domain, not an individual downstream service.

  • scope: Expresses the permissions associated with the transaction.

The specification defines request_context and request_details as recommended parameters. They give the TTS additional context about the transaction and request. In the playground, that information appears in the resulting transaction token as:

{
  "rctx": {
    "req_ip": "203.0.113.42",
    "authn": "urn:mace:incommon:iap:silver"
  },
  "tctx": {
    "action": "read",
    "resource": "/api/data"
  }
}

The TTS identifies the calling workload, sets req_wl, validates the subject context, creates a unique txn identifier, and issues the short-lived transaction token.

Step 3: Propagate the transaction token

The calling workload invokes a downstream service and sends the transaction token in the dedicated HTTP header:

GET /rs/api/data

Txn-Token: <transaction_token>

The use of a separate Txn-Token header is deliberate. Workloads mustn’t use the standard Authorization header to carry the Txn-Token because they might need that header for other purposes.

The receiving workload validates the transaction token before using it for authorization. It verifies:

  • Signature: Is the token cryptographically valid?

  • aud: Is it valid in this trust domain?

  • exp: Is it still current?

  • Transaction context: Does this context authorize the requested activity?

If the workload makes another downstream call as part of the same call chain, it propagates the transaction token onward unchanged to provide execution continuity.

How transaction tokens relate to other concepts

The difference between principals and requesting workloads

The TTS identifies the requesting workload using the req_wl claim. This answers which workload requested the transaction token.

This isn’t the same thing as the transaction principal. In a human-driven workflow, Sarah might be the sub, while the meeting prep agent is the req_wl. This separation is useful in AI systems because the workload executing a transaction and the principal associated with that transaction aren’t always the same.

Transaction tokens versus workload identity

A transaction token contains a req_wl claim identifying the requesting workload. This shouldn’t be confused with a complete workload identity system.

  • Workload identity defines which running workload this is.

  • Transaction tokens define the trusted transaction context the workload participates in.

In a broader architecture, SPIFFE can establish the identity of the workload requesting the transaction token. The TTS can use trusted workload authentication when deciding whether that workload is authorized to obtain one. These layers complement each other.

Transaction tokens and token exchange solve different problems

Transaction tokens use the Token Exchange protocol when requesting a token from the TTS, but the architectural purpose differs from the cross-domain token exchange pattern.

  • Cross-domain token exchange moves trusted identity and authorization into another trust domain.

  • Transaction tokens preserve trusted transaction context through a call chain within a trust domain.

Transaction tokens differ from ID-JAG

ID-JAG is used when delegated user identity and authorization need to cross into another authorization domain. Transaction tokens are scoped to one trust domain and carry transaction context through a call chain. A single enterprise AI workflow can use both, but at different points and for different reasons.

Key takeaways

Short lifetimes matter

Transaction tokens are deliberately short-lived. They aren’t intended to become a broadly reusable enterprise credential. The specification notes that transaction tokens aren’t inherently replay-resistant. Short lifetimes are therefore important, and the unique txn identifier supports auditing and replay detection.

Keeping the call chain understandable

Without transaction context, logs from a distributed AI workflow only show which services called each other. A shared txn identifier gives those calls a common transaction reference. When workloads log that identifier, the enterprise has a way to associate downstream activity with the transaction that caused it. This is valuable for debugging, authorization analysis, security investigation, and auditing.

Transaction tokens give the trust domain a way to keep context intact. The TTS creates a short-lived, signed token for the transaction that identifies the transaction principal, the requesting workload, the trust domain, and the authorized purpose. Workloads have identities and security controls of their own and the transaction token adds a trusted description of the transaction they’re currently participating in.