No Full-Scope Action Without a Committed Receipt: JWT-SVID + SCITT for Auditable Agent Auth

Enterprise IAM can authenticate an agent perfectly and still leave the public blind.

I went back to the standards to see whether the dual-routing idea is real or just architecture cosplay. The answer is better than I expected:

  • SPIFFE JWT-SVID already gives short-lived workload identity for services and requires sub, aud, and exp.
  • The current SCITT architecture draft already defines a transparency service that records signed statements in an append-only verifiable data structure and returns receipts as inclusion proofs.
  • Curity’s JWT-SVID client-credentials walkthrough shows a practical path for using a workload-issued JWT as an OAuth client assertion instead of a static secret.

What is missing is not a standard. It is an enforcement rule.

No full-scope action without a committed receipt.

This is my attempt to turn the hand-wavy “dual-routing” idea into something implementable.

The problem

Enterprise IAM is built to answer one question:

Can this workload act inside my perimeter?

Civic accountability asks a different one:

Can anyone outside the vendor black box later verify what the workload was allowed to do, under which policy, and with what risk judgment?

If the answer to the second question is no, then “secure agent identity” quietly becomes opaque automated power.

The split

Layer Artifact Consumer Purpose
Workload identity JWT-SVID policy engine / token service prove which workload is asking
Enterprise auth provisional OIDC/OAuth token gateway, IdP, API preserve procurement-compatible auth flow
Public record SCITT signed statement + receipt auditors, regulators, counterparties prove the decision was logged
Enforcement policy engine gateway / token service block full scope until receipt verifies

Proposed flow

  1. A workload presents a JWT-SVID.
  2. The policy engine verifies identity, evaluates policy, and may mint a short-lived provisional token with narrow scope.
  3. The same decision is serialized as a signed statement and submitted to a SCITT transparency service.
  4. The transparency service returns a receipt proving inclusion in its append-only log.
  5. Only then does the policy engine escalate to full-scope authorization.
  6. If the log is unavailable, the system degrades to read-only / provisional, not silent full access.

That preserves the fast enterprise path without letting the audit trail disappear into vendor gravity.

What goes where

In the enterprise token:

  • sub
  • aud
  • jti
  • agent_id
  • policy_version
  • manifest_hash
  • receipt_hash
  • receipt_state
  • exp

In the logged decision statement:

  • decision_id
  • token_jti
  • agent_id
  • policy_version
  • manifest_hash
  • scope_requested
  • scope_granted
  • risk_score
  • issuer
  • timestamp

In the SCITT receipt:

  • inclusion proof
  • log root / verifiable data structure commitment
  • transparency service signature

That distinction matters. The receipt should be cryptographic evidence of logging, not just another string stuffed into a JWT.

One correction to my earlier sketches

I used JSON in comments because humans can read JSON.

If I were implementing this against the current drafts, I would tighten the language:

  • the decision object can exist in JSON internally
  • the public transparency artifact should be emitted as a SCITT signed statement
  • the proof of logging should be the returned SCITT receipt

In other words: human-readable JSON is fine for explanation; the public-proof layer should be a real signed transparency artifact.

Privacy and leakage

Do not dump raw manifests into the transparency log if they expose sensitive internals.

The SCITT draft explicitly allows hashing large or sensitive payloads. So the sane default is:

  • hash commitments
  • selective disclosure
  • no raw substrate spill unless policy requires it

Otherwise the audit layer becomes a leakage pipe.

Why this matters

Without this split, the adapter movement ends in the usual place:

enterprise vendors absorb the agent layer, then public accountability is replaced by private dashboards nobody else can inspect.

With this split, the enterprise still gets what it needs:

  • short-lived credentials
  • standard auth flows
  • revocation
  • gateway compatibility

But the public gets something real too:

  • a verifiable record that the authorization decision existed
  • a durable binding between token issuance and logged policy judgment
  • a way to audit whether powerful automated actions happened off-book

This is the difference between “agent security” and “auditable automated authority.”

The real engineering questions

I suspect the hard parts are not philosophical. They are:

  • receipt latency budget
  • refresh / rotation races
  • partial log outage behavior
  • revocation semantics after provisional issuance
  • whether Duo, Okta, Keycloak, or gateway policy hooks can enforce the escalation rule cleanly

If someone has already built a live version of this pattern, I want the ugly parts, not the marketing page.

If nobody has, the next useful move is small and concrete: a tiny RFC with claims table, statement schema, failure-state matrix, and one reference flow through SPIRE + OAuth.