← Machine Authority Protocol
Machine Authority Protocol v1.0 Cryptographic Attestation of Consent (CAC) v1.0 Status: STABLE Published: 2026-05-03

Abstract

A Cryptographic Attestation of Consent is the signed receipt produced when an action is authorized — automatically (ALLOW) or after human approval (DEFER → APPROVE). A CAC binds the action hash, approver identity, decision, declared intent, timestamp, and policy version into a tamper-evident token verifiable by any auditor offline against the original CAR. It is not an access token: a CAC cannot be replayed against a different action.

CAC is the wire-format binding of AARM v1 §R3 (policy + intent evaluation, captured in intent_alignment) and §R5 (signed receipt of the human decision). The normative artifact for validation is schema/cac-v1.json.

1. Introduction

OAuth session tokens authenticate a person to a service. SPIFFE SVIDs authenticate a workload to other workloads. Neither describes what specific action a human (or an automated policy) consented to. When audit, regulator review, or post-incident forensics asks “did a human approve this?”, the only answers available today are SaaS database rows and screenshots — neither of which is portable, non-repudiable, or verifiable offline.

CAC produces a portable, non-repudiable, offline-verifiable artifact: one signed object that any auditor with the original CAR and the approver's public key can verify, end-to-end, with no callbacks to the issuing system. Approvals become evidence rather than configuration.

3. CAC body

Field Type Required Description
versionstringREQUIRED"1.0".
profilestringREQUIREDMAP-CAC-JWS-1 or MAP-CAC-DSSE-1. See §4.
car_hashstring (hex64)REQUIREDSHA-256 of the canonical CAR JSON (lowercase hex).
decisionstringREQUIREDALLOW (AAB issued without human review) or APPROVE (issued by approver after Loop).
approver_identityobjectREQUIREDSame identity union as CAR's actor ({spiffe_id} | {did} | {url}). For ALLOW, the AAB's identity.
decided_atstring (RFC 3339)REQUIREDWhen the decision was made.
policy_versionstringREQUIREDMUST equal the policy_version from the Decision Envelope.
session_idstringREQUIREDMUST equal the session_id from the CAR.
action_idstring (UUIDv4)REQUIREDMUST equal the action_id from the CAR.
intent_alignmentobjectREQUIREDSee §3.2 below. Wire-format binding of AARM v1 §R3.
envelopestringREQUIREDJWS Compact Serialization (MAP-CAC-JWS-1) or base64url-encoded DSSE envelope prefixed dsse: (MAP-CAC-DSSE-1).

3.2 intent_alignment

Field Type Required Description
declared_intentstringREQUIREDNatural-language intent surfaced to the approver.
intent_digeststring (hex64)REQUIREDSHA-256 over the UTF-8 bytes of declared_intent.
alignment_assertionstring (enum)REQUIREDAGENT_DECLARED, APPROVER_REWORDED, or INFERRED_FROM_PROMPT.
approver_acknowledgedbooleanREQUIREDWhether the approver clicked through with declared_intent visible. MUST be false for decision = "ALLOW".

intent_alignment is what makes a CAC a binding of consent rather than just authorization. Without it, two actions with the same car_hash but different framings to the human are indistinguishable in the audit trail. With it, an auditor can verify both the action and the framing under which the human said yes.

4. Encoding profiles

A v1 CAC is encoded under one of two profiles. Both profiles produce identical canonical body bytes; only the cryptographic envelope differs.

4.1 MAP-CAC-JWS-1 (REQUIRED for v1 implementations)

JWS Compact Serialization (RFC 7515) with detached payload (RFC 7797):

  • alg: EdDSA (Ed25519 curve).
  • typ: MAP-CAC-JWS-1.
  • kid: identifier resolvable to the approver's public key per §5.
  • b64: false, crit: ["b64"].
  • Payload: the canonical (RFC 8785 + NFC + empty-key strip) JSON of the CAC body minus the envelope field.
  • Compact form: <base64url-header>..<base64url-signature> with the empty middle segment marking detached payload.

4.2 MAP-CAC-DSSE-1 (OPTIONAL)

DSSE envelope around an in-toto Statement v1:

  • DSSE payloadType: application/vnd.in-toto+json.
  • predicateType: https://machineauthority.org/spec/cac/v1.
  • subject[0].digest.sha256: the CAC car_hash.
  • predicate: the CAC body minus envelope, canonicalized identically to the JWS profile.

The serialized DSSE envelope is base64url-encoded and set as the value of the CAC envelope field, prefixed with the literal string dsse: so verifiers can branch on profile without parsing the bytes twice.

Predicate byte-equality (NORMATIVE). The DSSE predicate bytes after canonicalization MUST equal the JWS-profile body bytes byte-for-byte. A verifier that observes a DSSE CAC whose predicate canonicalizes to anything other than the corresponding CAC body (e.g. decision rewritten between body and predicate) MUST return SCHEMA_VIOLATION — otherwise an attacker could ship a JWS body with one verdict and a DSSE predicate with another, and downstream tooling that consumes only one profile would observe two contradictory receipts under one envelope.

4.3 Why two profiles

JWS is the cheapest path to verification: every JOSE library on every platform consumes it, and a v1 verifier ships as a single command without external dependencies. DSSE drops into the existing supply-chain ecosystem (Sigstore, Rekor, cosign, in-toto) without adapter code. Picking one would alienate one ecosystem; the cost of supporting both is low because the body bytes are identical. A v1 verifier MUST accept JWS and MAY accept DSSE.

5. Verification

A verifier returns one of: OK, BAD_SIGNATURE, BAD_HASH, EXPIRED_KEY, UNRESOLVABLE_KID, SCHEMA_VIOLATION, INTENT_DIGEST_MISMATCH, UNRESOLVABLE_APPROVER_IDENTITY.

  1. Validate the CAC body against schema/cac-v1.json.
  2. Recompute car_hash from the supplied CAR using the canonicalizer (CAR §6).
  3. Verify action_id and session_id in the CAC equal the corresponding CAR fields.
  4. Recompute intent_digest as SHA-256 of declared_intent.
  5. Resolve approver_identity via the key resolution chain (§5.2).
  6. Locate the key matching the envelope's kid (or DSSE signatures[].keyid).
  7. Verify the envelope per §4.
  8. Check key validity windows (§5.3).
  9. Otherwise return OK.

5.2 Approver key resolution chain

  1. Embedded jwk (or DSSE cert) in the envelope (air-gapped only).
  2. kid → pinned organization registry / JWKS cache.
  3. SPIFFE bundle for the trust domain.
  4. DID resolver (verification method matching kid).
  5. <origin>/.well-known/map-approver-keys.json for URL-typed identities.
  6. Configured fallback (offline JWKS file).
  7. Otherwise fail UNRESOLVABLE_APPROVER_IDENTITY.

5.3 Validity windows

A CAC issued under a key valid at decided_at remains valid evidence after the key is rotated — the verifier's clock is not used to invalidate historical CACs. This matches the Sigstore/Fulcio model and lets CACs survive routine key churn.

6. Limitations

The following are explicitly out of scope for v1.0 and tracked on the post-v1.0 roadmap. They do not block v1 conformance.

  • Single signer only. Multi-signer / quorum-policy CACs are roadmap.
  • No transparency log requirement; an optional log profile is on the post-v1.0 roadmap.
  • Revocation is rotation-based via the JWKS revoked hint. Real-time revocation is roadmap.
  • Mandates Ed25519 only. Hybrid ML-DSA paths are roadmap.
  • Silent on HSM requirements; operators MAY require HSM-backed keys for high-risk approver cohorts.

6.1 Stability commitment

Breaking changes to the v1 CAC wire format require a 12-month deprecation window and a supermajority of the maintainer council before a v2 cutover. Conforming v1 verifiers MUST interoperate with conforming v1 signers without negotiation.

7. References