Agent + On-Behalf-Of + DPoP
An agent that exchanges a user token for a downstream token and binds every call to a private key.
Goal
Build an end-to-end OBO flow: user signs into a web app, app spawns an agent that calls a resource server "as Alice", with the agent identity preserved via act claim, and every token DPoP-bound. Audit logs prove who did what.
Stack
- IdP: Keycloak (with Token Exchange + DPoP enabled).
- App: SvelteKit / Next.js (PKCE flow).
- Agent runtime: Python (FastAPI + httpx).
- Resource server: FastAPI
tickets-apiwith JWT + DPoP validation. - Audit pipeline: Loki + Grafana.
Architecture
User → App (PKCE) → user_access_token (aud: app-api)
App → Token Exchange → agent_obo_token (sub=alice, act=agent.helpdesk-v1, aud=tickets-api)
Agent → DPoP-bound calls → tickets-api → Postgres
(each request includes a fresh DPoP header)
All services emit audit records → LokiBuild plan (5 days)
- Day 1: Keycloak realm + clients (
helpdesk-app,agent.helpdesk-v1) + APIs. Enable Token Exchange + DPoP. mkcert HTTPS. - Day 2: User-facing app with PKCE; show the user a session view. Server-side stores
user_access_tokenin Vault. - Day 3: Agent runtime: on user request, fetch user's token from Vault → Token Exchange → DPoP-bound calls to
tickets-api. - Day 4:
tickets-apivalidates: JWT signature,iss,aud,exp, scope, DPoPhtu/htm/ath. Emit structured audit logs withsub+act. - Day 5: Loki + Grafana dashboards: events per minute, deny rate, per-agent latency. Write README + threat model.
Acceptance criteria
- A token captured from the wire can't be replayed (different DPoP key fails).
- Removing
actfrom the OBO token → audit shows only user, breaking traceability — demonstrate fix. - Token Exchange downscoping works: requesting
tickets:writewhen subject token only hastickets:read→ IdP denies. - Audit log lets you reconstruct any agent action in < 1 minute.
Stretch
- Replace static client secret with SPIRE workload identity (lesson 2.2).
- Add CIBA for sensitive
delete_ticketaction. - Add a
actchain by spawning a sub-agent; observe nested claims. - Add Sigstore-signed Docker images + Kyverno admission.
Interview talking points
- Why
actclaim vs impersonation. - DPoP value proposition vs static bearer tokens.
- Why aliases + scopes coexist with claims-driven authz.
- Tradeoffs: refresh token lifetime vs UX vs theft risk.
- Audit log schema design.