ai-agents-for-beginners

Watch the lesson video: Securing AI Agents with Cryptographic Receipts

(Lesson video and thumbnail go add by Microsoft content team after dem combine am, e go follow the lesson 14 / 15 pattern.)

Securing AI Agents with Cryptographic Receipts

Introduction

Dis lesson go cover:

Learning Goals

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

The Problem: Your Agent’s Audit Trail

Imagine say you don deploy AI agent for Contoso Travel. Agent dey read customer request, call flights API to find options, and book seat for customer. For last quarter, agent process 50,000 bookings.

Today auditor show. Dem ask simple question: “Make you show me wetin your agent do.”

You give dem your log files. Auditor look am, then dem ask harder question: “How I know say dem no edit the log?”

Na so audit-trail problem be. Today, most agent deployment rely on:

None of these fit answer auditor question without auditor trusting somebody (you, your cloud provider, your database vendor). For internal use, dat trust fit make sense. For regulated workload dem (finance, healthcare, anything wey EU AI Act concern), e no fit.

Cryptographic receipts solve am because dem make each agent action fit verify on im own. Auditor no need trust you. Dem only need your public key and receipt itself.

What is a Cryptographic Receipt?

Receipt na JSON object wey record wetin agent do, and e dey sign with digital signature.

flowchart LR
    A[Agent dey use tool] --> B[Build receipt payload]
    B --> C[Canonicalize JSON RFC 8785]
    C --> D[SHA-256 hash]
    D --> E[Ed25519 sign]
    E --> F[Receipt wey get signature]
    F --> G[Auditor dey check offline]
    G --> H{Signature correct?}
    H -- yes --> I[Tamper-proof evidence]
    H -- no --> J[Receipt no clear]

Minimal receipt 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 properties dey do the work:

  1. Signature. Receipt na agent gateway dey sign am with Ed25519 private key. Anybody wey get public key fit verify signature offline. If tamper any field, signature no go valid again.

  2. Canonical encoding. Before sign, receipt go serialize with JSON Canonicalization Scheme (JCS, RFC 8785). Dis go make sure say two different implementation wey produce same logical receipt go produce byte-identical output. Without this canonicalization, different JSON serializers fit give different signatures for same content.

  3. Hash chaining. The previous_receipt_hash field link one receipt to receipt before am. If you comot or rearrange receipt, you go break every receipt wen come after am. Even if person bypass individual signature, tampering go dey obvious for chain level.

Dem three properties together dey give dis three guarantee:

Producing a Receipt in Python

You no need special library to produce receipt. Cryptographic primitives dey for everywhere and the logic na just small Python lines.

The hand-on exercises for code_samples/18-signed-receipts.ipynb go show you full flow. Summary version be:

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 load one signing key (for production, keep am for one 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,
}

# Canonicalize, hash, sign.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature

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

Na so d whole signing pipeline be. Exercises for notebook go show each step.

Verifying a Receipt and Detecting Tampering

Verification na opposite process:

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 structured object: {"alg", "sig", "public_key"}.
    sig_obj = receipt.get("signature")
    if not sig_obj or sig_obj.get("alg") != "EdDSA":
        return False

    # Make back di payload we dem really sign (everything but di signature).
    payload = {k: v for k, v in receipt.items() if k != "signature"}

    canonical_bytes = canonicalize(payload)
    message_hash = hashlib.sha256(canonical_bytes).digest()

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

This function go take receipt come give you True if signature valid, False if no valid. No network request, no service depend, no trust in anybody third party.

To see tampering detection, notebook go:

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

Dis na practical demonstration say receipt dey tamper-evident: any small modification fit break signature.

Chaining Receipts for Multi-Step Agents

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

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

Each receipt record hash of receipt before am. To comot receipt 2 quietly, attacker go need either:

If private key dey hardware key vault and you dey publish public key with each receipt, neither attack go possible without detection.

Notebook go:

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

Na so you produce audit trail wey external auditor fit verify without trust you.

What Receipts Prove (and What They Do Not)

Dis na most important part for dis lesson. Receipts strong but dem get limit.

Receipts dey prove three things:

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

Receipts no dey prove:

  1. Correctness: say the agent action be the right action. Receipt fit sign wrong answer as clean as correct answer.
  2. Policy compliance: say policy wey dem put for policy_id really evaluate, or say e for allow dis action if dem check am. Receipt record wetin dem claim, no be wetin dem enforce.
  3. Identity beyond key: receipt talk “dis key sign dis content.” E no talk “dis human authorize dis.” To connect key to person need separate identity system (directory, public key registry, etc).
  4. Truthfulness of inputs: If agent get manipulated prompt and act on am, receipt go record action faithfully. Receipts dey downstream of input validation, no be replacement.

Dis boundary important for two reasons:

Common mistake be say people think “we get receipts” mean “we dey governed.” Na lie. Receipts na foundation. Governance na system you build on top.

Production References

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

  1. Build directly on cryptographic primitives. The 50 lines wey you see on top enough for many use cases. PyNaCl (Ed25519) and jcs package (canonical JSON) na well maintained and audited library.

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

    • Receipt format for dis lesson follow IETF Internet-Draft (draft-farley-acta-signed-receipts) wey dey standard process.
    • Microsoft Agent Governance Toolkit dey combine receipts with Cedar-based policy decisions; see Tutorial 33 for repository for full example.
    • protect-mcp (npm) and @veritasacta/verify (npm) packages provide Node-based receipt signing and offline verification, to wrap MCP server with tamper-evident audit trail.

The choice between making your own and using library na like choice between writing your own JWT library and use tested one: both dey okay; library save time and reduce audit surface; from-scratch make you sabi every primitive. Dis lesson teach from-scratch so you get foundation for any choice.

Knowledge Check

Test your understanding before you move to practice exercise.

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

Answer Yes. Ed25519 verification need only public key and signed bytes. No network request, no service dependency. Na why receipt dey useful for air-gapped, multi-org, or low-trust audit setting.

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

Answer Verification go fail. Signature compute from canonical bytes for original payload; change any field change canonical bytes, change SHA-256 hash, make signature invalid. Attacker need private key to produce fresh valid signature, wey dem no get.

3. Why receipt dey include tool_args_hash and result_hash instead of raw arguments and result?

Answer Two reasons. First, receipt fit need archive or transmit for environment wey leaking raw content (PII, business data) no good. Hash keep receipt small and content private; auditor verify hash match separate stored copy of content. Second, hashes get fixed size; receipt with hashes no dey too big no matter how large input and output be.

4. previous_receipt_hash field link each receipt to predecessor. If attacker silently delete one receipt from middle of chain, wetin go become invalid?

Answer Every receipt after the deleted one. Their `previous_receipt_hash` no go match actual chain (because the receipt dem reference no dey, or chain this time link different one). To hide deletion, attacker go need re-sign every later receipt, wey need private key.

5. Receipt verify clean. E prove say agent action correct, sound, or follow policy?

Answer No. Valid receipt prove three things: attribution (dis key sign this content), integrity (content no change), ordering (receipt come after another). E no prove say action correct, policy for `policy_id` actually evaluate, or say agent follow every rule. Receipts make agent behaviour auditable, not necessarily correct. Na most important lesson boundary.

Practice Exercise

Open code_samples/18-signed-receipts.ipynb and complete all four sections:

  1. Section 1: Sign your first receipt and verify am.
  2. Section 2: Tamper receipt and see verification fail.
  3. Section 3: Build three-receipt chain and verify chain integrity.
  4. Section 4: Use pattern for agent built with Microsoft Agent Framework: wrap tool call in receipt-signing, then verify receipt independently.

Stretch challenge 1: expand receipt schema with extra field of your choice (for example, request ID for tracing), update canonical signing logic to include am, and check say receipt still fit verify. Then change field after signing and confirm verification fail. Dis one go make you understand how every byte for canonical encoding dey affect signature. Stretch challenge 2: SHA-256-hash two of your receipts together (concatenate their canonical bytes in a deterministic order) and embed the resulting digest as a new field on a third receipt before signing it. Verify say all three receipts still dey round-trip. You don just build one-step inclusion proof: anybody wey get the third receipt fit prove say the first two dey exist at the time e sign am, without needing to show their contents. Na di pattern wey selective-disclosure receipts dey use for large scale (Merkle commitments, RFC 6962).

Conclusion

Cryptographic receipts dey give AI agents audit trail wey be:

Dem no be replacement for input validation, policy enforcement, or identity infrastructure. Dem be foundation for those layers. When you dey deploy agents into regulated workloads, multi-organization workflows, or any place wey future auditor no go fit just trust you, receipts na how you fit keep audit trail honest.

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

Production Checklist

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

You Get More Questions About Securing AI Agents?

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

Beyond This Lesson

This lesson cover single-receipt signing and hash-chained sequences. The same primitives fit form plenty advanced patterns wey you fit see as your governance matures:

Additional Resources

Previous Lesson

Building Computer Use Agents (CUA)

Next Lesson

(To be determined by curriculum maintainers)


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.