Illustrative, runnable examples of the verification flow: a principal delegates scoped authority, the agent presents a proof-of-possession credential, the service verifies it, logs the action, and revocation is checked. Code is illustrative, not production-ready.
The examples follow the seven steps in How to verify an agent. They use a running example: an agent (`travelbot`) acting for a principal (`alice@example.com`) to make a booking on `travel.example.com`. Replace hosts, credentials and library calls with your own stack; the point is the shape of the checks, not the specific SDK.
Not production-ready. These snippets omit error handling, key management, retries and hardening. Do not copy them into production unchanged.
What each example shows
| Capability | What the code demonstrates | Standards |
|---|---|---|
| Delegation | Exchanging the principal’s token for a scoped, agent-specific token that records both actor and subject | RFC 8693 |
| Proof of possession | Binding a token to the agent’s key so a stolen token cannot be replayed | RFC 9449, RFC 8705 |
| Audit logging | Appending a tamper-evident, hash-chained record of who acted, for whom and when | Append-only logging practice |
| Revocation check | Asking the authorization server whether a token is still active before acting | RFC 7662, RFC 7009 |
curl
Delegation
“`bash
Exchange the principal’s token for a scoped, agent-specific token (RFC 8693).
curl -s https://auth.example.com/token \ -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \ -d subject_token=”$USER_ACCESS_TOKEN” \ -d subject_token_type=urn:ietf:params:oauth:token-type:access_token \ -d actor_token=”$AGENT_ASSERTION” \ -d actor_token_type=urn:ietf:params:oauth:token-type:jwt \ -d requested_token_type=urn:ietf:params:oauth:token-type:access_token \ -d scope=”bookings:write” “`
Proof of possession
“`bash
Present a DPoP-bound token to the service (RFC 9449).
curl -s https://travel.example.com/bookings \ -H “Authorization: DPoP $ACCESS_TOKEN” \ -H “DPoP: $DPOP_PROOF” \ -d ‘{“trip”:”HEL-BCN”,”max_eur”:1200}’ “`
Audit logging
“`bash
Record the action with actor, principal, decision and credential reference.
curl -s https://audit.example.com/events \ -H “Authorization: Bearer $AUDIT_TOKEN” \ -d ‘{“actor”:”spiffe://kya.fi/agents/travelbot”, “principal”:”alice@example.com”, “action”:”bookings:write”, “decision”:”allow”, “ts”:”2026-10-03T20:00:00Z”}’ “`
Revocation check
“`bash
Ask the authorization server whether the token is still active (RFC 7662).
curl -s https://auth.example.com/introspect \ -u “$CLIENT_ID:$CLIENT_SECRET” \ -d token=”$ACCESS_TOKEN” “`
Python
Delegation
“`python
Delegation: request a scoped, on-behalf-of token for the agent (RFC 8693).
import requests
resp = requests.post( “https://auth.example.com/token”, data={ “grant_type”: “urn:ietf:params:oauth:grant-type:token-exchange”, “subject_token”: user_token, # the principal “subject_token_type”: “urn:ietf:params:oauth:token-type:access_token”, “actor_token”: agent_assertion, # the agent “actor_token_type”: “urn:ietf:params:oauth:token-type:jwt”, “requested_token_type”: “urn:ietf:params:oauth:token-type:access_token”, “scope”: “bookings:write”, }, ) scoped_token = resp.json()[“access_token”] “`
Proof-of-possession verification
“`python
verify signature, audience, actor and scope before allowing the action
def verify(token, proof, request): assert token.aud == “travel.example.com” assert token.act == “spiffe://kya.fi/agents/travelbot” # the agent assert token.sub == “alice@example.com” # the principal assert request[“max_eur”] <= token.scope["max_eur"] return True ```
“`python
The DPoP proof must be signed by the key the token is bound to (RFC 9449).
def verify_dpop(token, proof, request): jwk = verify_jws(proof, typ=”dpop+jwt”) assert jwk[“thumbprint”] == token.cnf[“jkt”] # token bound to this key assert proof[“htm”] == request.method assert proof[“htu”] == request.url assert proof[“jti”] not in seen_jti # replay check “`
Audit logging
“`python
append-only, hash-chained audit entry
import hashlib, json, time
entry = { “actor”: “spiffe://kya.fi/agents/travelbot”, “principal”: “alice@example.com”, “action”: “bookings:write”, “at”: time.time(), “prev”: head, } entry[“hash”] = hashlib.sha256(json.dumps(entry, sort_keys=True).encode()).hexdigest() audit.append(entry) head = entry[“hash”] “`
Revocation check
“`python
Check the token is still active before acting (RFC 7662 introspection).
r = requests.post( “https://auth.example.com/introspect”, auth=(client_id, client_secret), data={“token”: token}, ) if not r.json().get(“active”, False): raise PermissionError(“token revoked or expired”) “`
JavaScript / TypeScript
Delegation
“`ts // Delegation: exchange for a scoped, on-behalf-of token (RFC 8693). const body = new URLSearchParams({ grant_type: “urn:ietf:params:oauth:grant-type:token-exchange”, subject_token: userToken, subject_token_type: “urn:ietf:params:oauth:token-type:access_token”, actor_token: agentAssertion, actor_token_type: “urn:ietf:params:oauth:token-type:jwt”, requested_token_type: “urn:ietf:params:oauth:token-type:access_token”, scope: “bookings:write”, }); const { access_token } = await fetch(“https://auth.example.com/token”, { method: “POST”, body, }).then((r) => r.json()); “`
Proof of possession
“`ts // Sign the request with the agent’s key so the token cannot be replayed (RFC 9449). const proof = await new SignJWT({ htm: “POST”, htu: url, jti: crypto.randomUUID() }) .setProtectedHeader({ alg: “ES256”, typ: “dpop+jwt”, jwk: publicJwk }) .setIssuedAt() .sign(privateKey); await fetch(url, { method: “POST”, headers: { Authorization: `DPoP ${accessToken}`, DPoP: proof }, }); “`
Audit logging
“`ts // append-only, hash-chained audit entry const entry = { actor, principal, action, at: Date.now(), prev: head }; entry.hash = sha256(JSON.stringify(entry)); audit.append(entry); “`
Revocation check
“`ts // Revocation check before acting (RFC 7662). const { active } = await fetch(“https://auth.example.com/introspect”, { method: “POST”, headers: { Authorization: `Basic ${basic}` }, body: new URLSearchParams({ token }), }).then((r) => r.json()); if (!active) throw new Error(“token revoked or expired”); “`
Go
Delegation
“`go // Delegation: token exchange (RFC 8693). form := url.Values{ “grant_type”: {“urn:ietf:params:oauth:grant-type:token-exchange”}, “subject_token”: {userToken}, “subject_token_type”: {“urn:ietf:params:oauth:token-type:access_token”}, “actor_token”: {agentAssertion}, “actor_token_type”: {“urn:ietf:params:oauth:token-type:jwt”}, “scope”: {“bookings:write”}, } resp, err := http.PostForm(“https://auth.example.com/token”, form) “`
Proof-of-possession verification
“`go // Verify the DPoP proof is bound to the token’s key (RFC 9449); illustrative only. thumb, err := jose.Thumbprint(proofJwk) if err != nil || thumb != token.ConfirmationKey { return ErrProofMismatch } “`
Audit logging
“`go // Audit trail: append-only, hash-chained entry. entry := AuditEntry{Actor: actor, Principal: principal, Action: action, Prev: head} sum := sha256.Sum256(mustJSON(entry)) entry.Hash = hex.EncodeToString(sum[:]) if err := audit.Append(ctx, entry); err != nil { return err } head = entry.Hash “`
Revocation check
“`go // revocation check before acting active, err := introspect(ctx, token) // RFC 7662 if err != nil || !active { return ErrRevoked } “`
Full reference implementations (Python, JavaScript/TypeScript, curl, Go) and an interactive walkthrough live in the project repository under `examples/`.
FAQ
Are these examples production-ready?
No. They are deliberately short to show the shape of each check. They omit error handling, key management, retry/backoff, clock-skew tolerance and hardening. Treat them as a starting sketch, not a library.
Which standard covers delegation versus impersonation?
OAuth 2.0 Token Exchange (RFC 8693) defines the request and token semantics, including the distinction between impersonation and delegation. It is designed so a downstream service can tell who is acting and on whose behalf.
How is proof of possession enforced?
For sender-constrained OAuth tokens, DPoP (RFC 9449) binds the token to a key the client holds and the server verifies per request; mutual-TLS (RFC 8705) binds the token to a client certificate instead. Either way, a stolen bearer token alone is not enough to act.
How do I check revocation?
Introspection (RFC 7662) lets a resource server ask the authorization server whether a token is still active; the revocation endpoint (RFC 7009) lets a client invalidate a token and, where applicable, other tokens from the same grant. Short-lived credentials reduce reliance on revocation lists because they expire on their own. See scoped credentials and the audit trail in the glossary, and why agent identity is new for the reasoning behind these controls.
Sources
- IETF, “RFC 8693: OAuth 2.0 Token Exchange” — https://www.rfc-editor.org/rfc/rfc8693.html (accessed 2026-10-03)
- IETF, “RFC 9449: OAuth 2.0 Demonstrating Proof of Possession (DPoP)” — https://www.rfc-editor.org/rfc/rfc9449.html (accessed 2026-10-03)
- IETF, “RFC 8705: OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens” — https://www.rfc-editor.org/rfc/rfc8705.html (accessed 2026-10-03)
- IETF, “RFC 7662: OAuth 2.0 Token Introspection” — https://www.rfc-editor.org/rfc/rfc7662.html (accessed 2026-10-03)
- IETF, “RFC 7009: OAuth 2.0 Token Revocation” — https://www.rfc-editor.org/rfc/rfc7009.html (accessed 2026-10-03)
- IETF, “RFC 9396: OAuth 2.0 Rich Authorization Requests” — https://www.rfc-editor.org/rfc/rfc9396.html (accessed 2026-10-03)
- SPIFFE project, “SPIFFE Concepts” — https://spiffe.io/docs/latest/spiffe-about/spiffe-concepts/ (accessed 2026-10-03)
- W3C, “Verifiable Credentials Data Model v2.0” — https://www.w3.org/TR/vc-data-model-2.0/ (accessed 2026-10-03)
- Model Context Protocol, “Authorization” — https://modelcontextprotocol.io/specification/draft/basic/authorization (accessed 2026-10-03)
Know Your Agent (KYA) explains agent identity, verification and accountability. This is an explainer, not legal or compliance advice — see our Sources & methodology. New to KYA? Start with What is Know Your Agent? and the glossary.