Building and proving the complete request path
The previous articles covered the identity model, PingFederate token exchange, SPIRE workload identity, and PingAuthorize policy. This final part connects them into one testable application path.
The application flow
The browser workbench signs the user in through PingFederate with OAuth 2.0 Authorization Code and PKCE. The application never collects the user's PingFederate password.
After sign-in:
- the demo agent receives the user access token
- the agent obtains a JWT-SVID from SPIRE
- PingFederate, acting as the TTS, exchanges the subject and actor evidence for a short-lived Txn-Token
- the agent sends that token in the
Txn-Tokenheader while calling the MCP gateway over SPIFFE mTLS - the gateway validates the transaction token and immediate caller
- OPA or PingAuthorize evaluates the verified target and tool request
- the gateway forwards the unchanged transaction token to the MCP server over mTLS
- the MCP server calls the protected API over another authenticated mTLS hop
The original user access token does not travel beyond the exchange. The Txn-Token does not become a browser session token, does not use the Authorization header for internal propagation, and is not rewritten by intermediaries.
A UI that shows evidence without exposing credentials
The workbench uses two-thirds of the screen for service interaction and one-third for a selectable audit trail. Events correlate the same transaction ID across the agent, gateway, MCP server, API, and authorization decision.
Selecting an event can show safe request and response metadata plus decoded, allowlisted token claims. It must not expose raw access tokens, JWT-SVIDs, transaction JWTs, authorization headers, cookies, authorization codes, client secrets, refresh tokens, private keys, or sensitive tool arguments.
Decoded claims are evidence for a human operator, not a new authorization input. Services authorize only after cryptographic validation.
Repository-owned product startup
Both Ping products use digest-pinned images and read-only repository-owned profile overlays.
PingFederate startup builds and tests the custom token processor plugin. Its Terraform configuration remains a separate explicit step.
PingAuthorize starts with a repository-owned deployment package selected during first setup. The package is mounted read-only, and the container joins only the expected local application bridge network.
Secrets, licenses, generated certificates, private keys, Terraform state, and discovery output remain outside Git.
Testing the security statement
The main authorization statement is:
verified transaction context
AND verified immediate caller
AND target policy
The end-to-end suite therefore needs more than a success case. It proves rejection for:
- forged logical agent identity
- wrong SPIFFE workload
- expired transaction token
- wrong audience
- unapproved MCP target
- stolen transaction token presented by the wrong mTLS caller
- direct agent-to-API access when only the MCP server is allowed
- malformed or contradictory authorization decisions
It also proves that one transaction ID appears across all expected hops and that captured logs contain no raw token material.
The PingFederate clean-bootstrap test goes further by recreating the product on an isolated volume and Terraform state, applying managed TLS, completing a live exchange, rejecting a tampered actor token, and cleaning only its randomly named resources.
The broader lesson
Agent security is not solved by adding an agent_id claim or passing a user token farther downstream. The implementation needs distinct evidence for the user, logical agent, workload, transaction, and immediate caller.
PingFederate provides the controlled delegation boundary. SPIRE proves runtime identity. PingAuthorize evaluates the verified action context. The gateway preserves the boundary between identity verification, routing, and policy enforcement.
Together, they make an agent action explainable and testable: who authorized it, which agent was approved, which workload ran it, why the transaction exists, which service made each call, and which policy allowed or denied the operation.
Previous: Making policy decisions with PingAuthorize
Return to the series index.
GitHub Repository: https://github.com/darkedges/pf-tts
Top comments (0)