{"id":12642,"date":"2026-07-09T20:47:27","date_gmt":"2026-07-10T01:47:27","guid":{"rendered":"https:\/\/www.rushworth.us\/lisa\/?p=12642"},"modified":"2026-11-02T10:05:36","modified_gmt":"2026-11-02T15:05:36","slug":"spire-follow-one-request-the-complete-trust-boundary-walkthrough","status":"publish","type":"post","link":"https:\/\/www.rushworth.us\/lisa\/?p=12642","title":{"rendered":"SPIFFE: Follow One Request: The Complete Trust-Boundary Walkthrough"},"content":{"rendered":"<p>An end-to-end walkthrough reveals mistakes that component diagrams hide. Document one successful delegated request, including every credential accepted, every identity transformation, and every independent authorization decision.<\/p>\n<h2>The delegated request sequence<\/h2>\n<p>1 Lisa \u2192 human authorization flow: authenticate and approve delegation<br \/>\n2 XYZ \u2192 local SPIRE Workload API: obtain agent credential<br \/>\n3 XYZ \u2192 PingFederate STS: subject token + actor evidence + target<br \/>\n4 STS: validate inputs; check pairing, approval, target, permissions<br \/>\n5 STS \u2192 XYZ: access token for the tool service<br \/>\n6 XYZ \u2192 tool: present token and any required possession proof<br \/>\n7 Tool: validate token; authorize requested operation<br \/>\n8 Tool \u2192 STS\/API: use an explicitly permitted downstream flow<br \/>\n9 API: independently validate and authorize case\/4821 mutation<br \/>\n10 Each boundary: preserve verified attribution and outcome<\/p>\n<p>The published IdP integration separates subject and actor token processing, exchange policy, and access-token-manager mapping. Treat those as distinct review points rather than assuming that one successful token validation authorizes the complete workflow.<\/p>\n<h2>Credential-validation matrix<\/h2>\n<table>\n<tbody>\n<tr>\n<td width=\"221\"><strong>Credential<\/strong><\/td>\n<td width=\"221\"><strong>Recipient<\/strong><\/td>\n<td width=\"221\"><strong>Required deployment contract<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>Lisa\u2019s eligible subject token<\/strong><\/td>\n<td width=\"221\">STS subject-token processor<\/td>\n<td width=\"221\">Trusted user issuer\/profile and exchange eligibility<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>XYZ JWT-SVID<\/strong><\/td>\n<td width=\"221\">STS actor-token processor<\/td>\n<td width=\"221\">Trusted SPIFFE authority; intended STS audience; actor mapping<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>OAuth client authentication<\/strong><\/td>\n<td width=\"221\">STS client-authentication boundary<\/td>\n<td width=\"221\">Authorized client; explicit relationship to actor if required<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>Tool access token<\/strong><\/td>\n<td width=\"221\">Tool service<\/td>\n<td width=\"221\">Its own audience; permitted subject\/actor; operation constraints<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>API access token<\/strong><\/td>\n<td width=\"221\">Resource API<\/td>\n<td width=\"221\">API audience; resource and mutation authorization<\/td>\n<\/tr>\n<tr>\n<td width=\"221\"><strong>Transport certificate or DPoP proof<\/strong><\/td>\n<td width=\"221\">Supporting recipient<\/td>\n<td width=\"221\">Required key\/token binding and proof validation<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>A JWT-SVID identifies its subject using the SPIFFE ID and includes an audience for the intended verifier. It is not automatically an OAuth access token for every API. Acceptance at an STS requires an agreed validation and trust profile.<\/p>\n<h2>Trace the identities without collapsing them<\/h2>\n<pre>{\r\n\"sub\": \"user:lisa\",\r\n\"aud\": \"case-management-api\",\r\n\"client_id\": \"agent-xyz-client\",\r\n\"scope\": \"cases.read cases.update\",\r\n\"act\": {\r\n\"sub\": \"spiffe:\/\/agents.example.org\/agent\/xyz\"\r\n},\r\n\"delegation_id\": \"approval-81a6\"\r\n}<\/pre>\n<p>This is an illustrative output payload, not a complete token profile. delegation_id is an application-defined extension. The outer subject represents Lisa; act identifies the current actor. Client identity identifies the OAuth client. The authenticated transport peer may be a tool service rather than the original agent. Retain those distinctions in policy and logs. RFC 8693 provides delegation semantics; application approval is a separate deployment concern. [6]<\/p>\n<h2>Standalone and asynchronous alternatives<\/h2>\n<p>For standalone work, authorize XYZ under an agent-specific policy rather than borrowing Lisa\u2019s authority. The API may directly accept SPIFFE authentication or accept an STS-issued token whose subject is the agent. This choice depends on the API\u2019s supported credential profiles, not on a universal SPIFFE requirement.<\/p>\n<p>If the tool receives an opaque token, use trusted introspection and check its result according to the agreed profile. Introspection is not a reason to omit audience or operation checks. Its response and any caching policy become part of the authorization boundary. [7]<\/p>\n<p>For queued work, protect the job\u2019s identity and approval context from modification, then re-evaluate authorization at execution time. A string saying user:lisa in a message is not a credential. Record both the originating agent and the executing worker; do not silently pretend that the worker is still the original transport caller.<\/p>\n<p>Takeaway: each hop must know what evidence it receives, what authority it establishes, and what authority it is allowed to pass onward.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An end-to-end walkthrough reveals mistakes that component diagrams hide. Document one successful delegated request, including every credential accepted, every identity transformation, and every independent authorization decision. The delegated request sequence 1 Lisa \u2192 human authorization flow: authenticate and approve delegation 2 XYZ \u2192 local SPIRE Workload API: obtain agent credential 3 XYZ \u2192 PingFederate STS: &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2243],"tags":[2246,2244,2216,2245],"class_list":["post-12642","post","type-post","status-publish","format-standard","hentry","category-spiffe","tag-agent-identity","tag-spiffe","tag-spire","tag-workload-identity"],"_links":{"self":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12642","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12642"}],"version-history":[{"count":2,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12642\/revisions"}],"predecessor-version":[{"id":12666,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=\/wp\/v2\/posts\/12642\/revisions\/12666"}],"wp:attachment":[{"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12642"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rushworth.us\/lisa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}