ai-agents-for-beginners

Watch di lesson video: Securing AI Agents wit Cryptographic Receipts

(Lesson video and thumbnail go add by Microsoft content team afta merge, weh go match lesson 14 / 15 pattern.)

Securing AI Agents wit Cryptographic Receipts

Introduction

Dis lesson go cover:

Learning Goals

After you finish dis lesson, you go sabi how to:

Di Problem: Your Agent’s Audit Trail

Make you imagine say you don deploy AI agent for Contoso Travel. Di agent dey read customer requests, e dey call flights API to look options, and e dey book seats for customers on their behalf. For last quarter, di agent process 50,000 bookings.

Today, auditor don show. Dem ask one simple question: “Show me wetin your agent do.”

You give dem your log files. Auditor look dem then ask harder question: “How I fit know say nobody edit dia logs?”

Dis na di audit-trail problem. Most agent deployments today dey rely on:

None of these fit answer auditor question without auditor to trust person (you, your cloud provider, your database vendor). For internal use, dat trust dey okay. For regulated workloads (finance, healthcare, anything wey dem dey subject to EU AI Act), e no dey okay.

Cryptographic receipts solve dis by making every agent action independently verifiable. Auditor no need trust you. Dem just need your public key and di receipt itself.

Wetin be Cryptographic Receipt?

Receipt na JSON object wey record wetin agent do, and e get digital signature.

flowchart LR
    A[Agent dey use tool] --> B[Build receipt payload]
    B --> C[Make JSON standard like for RFC 8785]
    C --> E[Ed25519 sign di standard bytes]
    E --> F[Receipt wey get signature]
    F --> G[Auditor dey check am offline]
    G --> H{Signature correct?}
    H -- yes --> I[Proof wey no fit change]
    H -- no --> J[Receipt reject]

Minimal receipt dey look like dis:

{
  "type": "agent.tool_call.v1",
  "agent_id": "contoso-travel-bot",
  "tool_name": "lookup_flights",
  "tool_args_hash": "sha256:a3f9c1...",
  "result_hash": "sha256:7b2e1d...",
  "policy_id": "contoso-travel-policy-v3",
  "timestamp": "2026-04-25T14:30:00Z",
  "sequence": 47,
  "previous_receipt_hash": "sha256:9d4e6a...",
  "signature": {
    "alg": "EdDSA",
    "sig": "c5af83...",
    "public_key": "8f3b2c..."
  }
}

Three things dey work:

  1. The signature. Di receipt sign by agent’s gateway using Ed25519 private key. Anybody wey get di public key fit verify di signature offline. If tamper with any field, di signature no go valid.

  2. Canonical encoding. Before dem sign am, receipt serialize using JSON Canonicalization Scheme (JCS, RFC 8785). Dis make sure sey two implementation wey produce same logical receipt go always produce byte-identical output. If no canonicalization, different JSON serializer go produce different signatures for same content.

  3. Hash chaining. Di previous_receipt_hash field bind receipt to di one before am. If person remove or reorder receipt, e break every receipt wey come after am. Tampering go show well well for di whole chain even if individual signature jam problem.

Together, dis things dey give three guarantees:

How to Produce Receipt for Python

You no need special library to make receipt. Cryptographic primitives dey available well and di logic na few dozen lines for Python.

Hands-on exercises for code_samples/18-signed-receipts.ipynb go show whole flow. Di summary version:

import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize  # RFC 8785 canonical JSON

def b64url_nopad(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")

def sha256_canonical(obj) -> str:
    """SHA-256 of a Python object's JCS-canonical JSON form."""
    return f"sha256:{hashlib.sha256(canonicalize(obj)).hexdigest()}"

# Make or find one signing key (for production, keep am for key vault)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key

# Build the receipt payload (no signature yet)
tool_args = {"origin": "SYD", "destination": "LAX"}
tool_result = [{"flight": "QF11", "price": 1850, "stops": 0}]

payload = {
    "type": "agent.tool_call.v1",
    "agent_id": "contoso-travel-bot",
    "tool_name": "lookup_flights",
    "tool_args_hash": sha256_canonical(tool_args),
    "result_hash": sha256_canonical(tool_result),
    "policy_id": "contoso-travel-policy-v3",
    "timestamp": "2026-04-25T14:30:00Z",
    "sequence": 0,
    "previous_receipt_hash": None,
}

# Make am proper and sign the JCS bytes straight. PureEdDSA de hash am inside.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).signature

# Put one structured signature object.
receipt = {
    **payload,
    "signature": {
        "alg": "EdDSA",
        "sig": b64url_nopad(signature_bytes),
        "public_key": b64url_nopad(bytes(verify_key)),
    },
}

Na di whole signing pipeline be dat. Exercises for notebook go break down every step.

Verifying Receipt and Detecting Tampering

Verification na reverse operation:

import base64
import hashlib
from nacl import signing
from nacl.exceptions import BadSignatureError
from jcs import canonicalize

def b64url_decode(s: str) -> bytes:
    padding = "=" * ((4 - len(s) % 4) % 4)
    return base64.urlsafe_b64decode(s + padding)

def verify_receipt(receipt: dict) -> bool:
    # Di signature na one structured object: {"alg", "sig", "public_key"}.
    sig_obj = receipt.get("signature")
    if not sig_obj or sig_obj.get("alg") != "EdDSA":
        return False

    # Make di payload wey dem really sign again (everything wey no be signature).
    payload = {k: v for k, v in receipt.items() if k != "signature"}

    canonical_bytes = canonicalize(payload)

    try:
        verify_key = signing.VerifyKey(b64url_decode(sig_obj["public_key"]))
        verify_key.verify(canonical_bytes, b64url_decode(sig_obj["sig"]))
        return True
    except BadSignatureError:
        return False

Dis function go take receipt and return True if signature valid, False if no valid. No network call, no service dependency, no trust for any third party.

To see tampering detection in action, notebook go do:

  1. Produce valid receipt and confirm say e verify.
  2. Modify one byte for tool_args_hash field.
  3. Re-run verification and see e fail.

Dis na practical show say receipts dey tamper-evident: any small modification go break di signature.

Chaining Receipts for Multi-Step Agents

One signed receipt dey protect one action. Chain of receipts dey protect sequence of actions.

flowchart LR
    R0[Receipt 0<br/>genesis] --> R1[Receipt 1]
    R1 --> R2[Receipt 2]
    R2 --> R3[Receipt 3]
    R1 -. previous_receipt_hash .-> R0
    R2 -. previous_receipt_hash .-> R1
    R3 -. previous_receipt_hash .-> R2

Every receipt dey record hash of di receipt before am. To remove receipt 2 without noise, attacker must either:

If private key dey hardware key vault and you publish public key with every receipt, nobody go fit do dis attack without dem knowing.

Notebook go show:

  1. Build chain of three receipts.
  2. Verify say each receipt previous_receipt_hash match actual hash of prior receipt.
  3. Tamper with one receipt for middle and see chain break for dat point.

Dis na how you produce audit trail wey external auditor fit verify without trust you.

Wetin Receipts Prove (and Wetin Dem No Prove)

Dis na di most important section for dis lesson. Receipts dey powerful but power no unlimited.

Receipts prove three tins:

  1. Attribution: specific key sign specific payload.
  2. Integrity: payload never change since signing.
  3. Ordering: dis receipt come after dat receipt for hash chain.

Receipts no prove:

  1. Correctness: say agent action na di right action. Receipt fit sign wrong answer same way as right one.
  2. Policy compliance: say policy wey dem talk for policy_id really evaluate, or say e for allow this action if dem check. Receipt record wetin dem claim, no wetin dem enforce.
  3. Identity beyond key: receipt talk “dis key sign dis content.” No talk “dis human authorize this.” To connect key with person or organization, you need separate identity infrastructure (directory, public key registry etc.).
  4. Truthfulness of inputs: if agent get manipulated prompt and act on top am, receipt go record action true true. Receipts dey downstream of input validation, no be replacement for am.

Dis boundary important for two reasons:

Common mistake na to think say “we get receipts” mean “we get governance.” No mean so. Receipts na foundation. Governance na di system wey you build on top.

Proving Human Approved Di Exact Action

Item 3 for above deserve im own section: action receipt talk “dis key sign dis content,” never “human authorize dis.” For high-risk actions (refunds, deletions, wire transfers), governance frameworks dey require exactly dis missing statement, and you fit produce am with di same primitives wey you don build for dis lesson.

Di next notebook code_samples/human-authorization-receipts.ipynb add second receipt kind, human.approval.v1, for same envelope shape like lesson receipts (typed payload signed by Ed25519 over im canonical JCS bytes, with signature object outside signed bytes). Named approver sign full canonical action and e digest before execution; agent’s action receipt get same action digest and parent_approval_ref, di receipt_hash of approval, di same convention like previous_receipt_hash for chain wey you don build above. One verify_chain dey check both artifacts under separate pinned key registries (approver keys vs agent keys), so code path na one but authorities no dey the same.

Di property dis buy, na say: human approve dis exact action, and agent execute exactly dat approved action. Notebook refusal features na wetin make dis property real instead of just claim:

Every failure refuse for different reason, so auditor fit tell if authority stale or action change. Rule for notebook: signed approval no be authority on im own. Authority dey only if both receipts still bind same canonical action during execution. Human-approval receipt na educational composition from dis lesson, no be receipt type from draft-farley-acta-signed-receipts.

Production References

Di Python code for dis lesson na minimal on purpose so you fit read every line and understand wetin dey happen. For production, you get two options:

  1. Build directly on cryptographic primitives. Di 50 lines wey you see above dey enough for many cases. PyNaCl (Ed25519) and jcs package (canonical JSON) be well-maintained and audited libraries.

  2. Use production receipt library. Some open-source projects sabi implement di same pattern with more features (key rotation, batch verification, JWK Set distribution, integration with policy engines):

    • Di signing pipeline use JCS and signature-scope conventions for independent IETF Internet-Draft (draft-farley-acta-signed-receipts, revision 02). Dis lesson flat educational receipt different from draft {payload, signature} envelope and no dey present as conformant implementation. Di draft publish shared conformance suite (agent-governance-testvectors) for implementations wey target e wire format.
    • Microsoft Agent Governance Toolkit dey compose receipts with Cedar-based policy decisions; you fit see Tutorial 33 inside dat repository for full example.
    • protect-mcp (npm) and @veritasacta/verify (npm) packages provide Node-based implementation of receipt signing and offline verification, meant to wrap any MCP server with tamper-evident audit trail, including held-for-co-sign flow wey paused action fit emit approval receipt bound to action digest (WebAuthn-backed for desktop flow), same approval-receipt pattern like human-authorization notebook above.
    • nobulex Python SDK (pip install nobulex) provide same Ed25519 + JCS signing pattern for Python with LangChain and CrewAI integrations, plus published cross-validation test vectors and compliance mapping from OWASP PR #2210.

Decision between build your own and use library na like decision between write your own JWT library and use tested one: both correct; library go save time and reduce audit surface; from-scratch go force you understand every primitive. Dis lesson teach from-scratch way so you get foundation for either choice.

Knowledge Check

Test your understanding before you enter practice exercise.

1. Receipt na sign with agent private Ed25519 key. Auditor get only public key. Auditor fit verify receipt offline?

Answer Yes. Ed25519 verification only need public key and signed bytes. No network call, no service dependency. Dis na wetin make receipts useful for air-gapped, multi-organization or low-trust audit.

2. Attacker modify policy_id field of receipt to claim say policy na more permissive one. Signature na over original payload. Wetin go happen during verification?

Answer Verification no pass. Di signature na over di canonical bytes of di original payload; if you change any field e go change di bytes dem, and dat go make di signature no valid. Di attacker need di private key to fit produce new valid signature, but dem no get am.

3. Why di receipt get tool_args_hash and result_hash instead of di raw arguments and result?

Answer Two reasons. First, di receipt fit need to be archived or sent for place wey to leak di raw content (PII, business data) be wahala. Hashing dey keep di receipt small and di content private; di auditor go verify say di hash match a copy of di real content wey dem store separately. Second, hashes get fixed size; receipt wey get hashes get limited size no matter how big di input and output be.

4. Di previous_receipt_hash field connect each receipt to di one wey come before am. How if attacker quietly comot one receipt from di chain middle, wetin go become invalid?

Answer All di receipts wey come after di one wey dem delete. Their `previous_receipt_hash` no go match di real chain again (because di receipt wey dem talk about no dey again, or di chain don direct to different predecessor). To hide di delete, di attacker must re-sign every later receipt, and that need di private key.

5. If receipt verify well, e mean say di agent action correct, sound, or comply wit policy?

Answer No. Valid receipt dey prove three things: attribution (this key sign this content), integrity (content no change), and ordering (this receipt follow that one after). E no mean say di action correct, or di policy wey dey `policy_id` really check, or say agent follow every rule. Receipt dey make agent behavior fit dey audited, no mean say e correct. Dis na di most important boundary for dis lesson.

Practice Exercise

Open code_samples/18-signed-receipts.ipynb and finish all four parts:

  1. Section 1: Sign your first receipt and verify am.
  2. Section 2: Change di receipt small and watch verification fail.
  3. Section 3: Build chain wey get three receipts and check di chain integrity.
  4. Section 4: Use di pattern with agent wey built with Microsoft Agent Framework: put tool call inside receipt-signing, then verify di receipt separately.

Stretch challenge 1: Add one more field you choosen for di receipt schema (like a request ID to trace), change di canonical signing logic to include am, then confirm say receipt still verify correct way. Then change di field after signing and confirm verification no pass. Dis go make you sabi how every byte for canonical encoding dey contribute to di signature.

Stretch challenge 2: SHA-256-hash two of your receipts together (join their canonical bytes in deterministic order) and put di resulting digest as new field for third receipt before you sign am. Verify all three receipts still dey fine. You don build one step inclusion proof: anyone wey get third receipt fit prove first two really exist when dem sign am, without showing their content. Dis na di pattern wey selective-disclosure receipts use for big scale (Merkle commitments, RFC 6962).

Conclusion

Cryptographic receipts dey give AI agents audit trail wey:

Dem no be replacement for input validation, policy enforcement, or identity system. Dem na foundation for those layers. When you dey deploy agents for regulated work, multi-organization workflow, or any place where future auditor no fit trust you, receipts be how you make audit trail honest.

Most important tori be say: receipts dey prove who talk wetin, when. Dem no prove say wetin dem talk na true or correct. Make you hold dat one tight. Na difference between honest provenance system and one wey dey mislead.

Production Checklist

When you ready to graduate from dis lesson to deploy receipt-signed agents for real:

You get more Questions about Securing AI Agents?

Join di Microsoft Foundry Discord to meet other learners, attend office hours, and get your AI Agents questions answered.

Beyond This Lesson

Dis lesson cover single receipt signing and hash-chained sequences. Di same primitives fit build more advanced patterns you fit see as your governance style grow:

Additional Resources

Previous Lesson

Creating Local AI Agents


Disclaimer: Dis document don translate wit AI translation service Co-op Translator. Even tho we dey try make am correct, abeg make you know say automated translation fit get errors or mistakes. Di original document for dia own language na im be di correct source. For important info, make person wey sabi human translation do am. We no go responsible for any misunderstanding or wrong understanding wey fit happen because of dis translation.