Vote for your favorite SkillMD. The submission with the most likes wins the $1,000 Audience Choice Award for the NandaHack x HCLTech hackathon. Voting is open through September 25.Vote now →
in reviewhumanPR #70Auth

fayner-delegatable-auth: macaroon capability tokens with cascading revocation (problem 04)

Problem: #04 — Delegatable capability tokens with cascading revocation (auth layer).

Author

faynercosta avatar

@faynercosta

github profile →
Status
In review
Opened on
Jul 5
Branch
hackathon/fayner-delegatable-auth

Description

The pitch.

# [Hackathon] fayner-delegatable-auth: macaroon capability tokens with cascading revocation

**Problem:** #04 — Delegatable capability tokens with cascading revocation (auth layer).
**Persona:** authorization-infrastructure engineer. The risk model, the test
emphasis (adversarial subset/revocation/audience invariants), and the
macaroon idioms below are the submission, not a label on a generic plugin.

> **Naming note (post-#138):** while this PR was in review, #138 merged an
> independent problem-04 solution under `auth/delegatable.py`,
> `DelegatableAuth`, `("auth", "delegatable")` and the `delegated_auth`
> scenario. This submission keeps its implementation unchanged and takes a
> distinct, honest identity so both plugins coexist: **`MacaroonAuth`**,
> registered as **`("auth", "macaroon")`** (the mechanism *is* a macaroon;
> the name says so), with the **`capability_delegation`** scenario — matching
> the problem brief's own slug, `04-auth-capability-delegation`.

## What sets this apart from the other problem-04 submissions

Most delegatable-token PRs (including strong ones) stop at "the HMAC chain
verifies." This one is built around the observation that **the chain proves
provenance, not permission** — any holder can extend the chain with whatever
link they like and compute a perfectly valid signature. Concretely:

1. **Verify-side semantic re-walk.** `verify` independently re-checks scope
   subsets, TTL nesting, and delegator→audience linkage across *every* link,
   so a forged-but-chain-valid broadening link is rejected
   (`test_scope_escalation_rejected_at_verify_when_chain_tampered` exercises
   exactly this, with a hand-forged HMAC-valid token).
2. **Both directions of the adversarial bar are demonstrated, not asserted.**
   Every attack probe runs against *both* plugins through small adapters
   (`macaroon_delegate`/`presenter_verify` vs `naive_jwt_delegate`/
   `blind_verify`): the probes pass against `macaroon` **and** fail against
   the reference `jwt`, in the same test run.
3. **Offline trace-replay validator.** The scenario's gatekeeper emits a
   one-line audit protocol; `validate_capability_delegation_trace` replays it
   offline and independently decides pass/fail — it FAILS on the `jwt` arm
   and PASSES on the `macaroon` arm.
4. **Four Hypothesis properties** (subset invariant at every depth, monotone
   revocation cascade, deterministic token construction, escalation always
   rejected) on top of the unit and end-to-end suites.
5. **Determinism in both arms, asserted.** Byte-identical traces are asserted
   for the `macaroon` *and* the `jwt` arm — the reference plugin is pinned to
   the logical clock at provisioning (`clock=0.0`), so no wall-clock leaks
   into any trace this scenario writes.

## Motivation

The default `jwt` plugin can mint and revoke flat tokens, but it cannot model
the single most common multi-agent authorization pattern: an orchestrator
holding a long-lived root capability, minting narrowly-scoped, short-lived
sub-capabilities for worker agents **without going back to the issuer**, and
having a single `revoke(parent)` cascade to every descendant. `JwtAuth._revoked`
is a set of exact token strings with no parent-child relationship, so revoking a
parent leaves its delegated children valid — the exact gap the problem calls
out, and the gap that makes "an LLM agent sub-renting a tool and cleanly
withdrawing it" impossible to express today.

## Design

`MacaroonAuth` is a macaroon (Birgisson et al., NDSS 2014): a token is a
chain of links, each an attenuating caveat, secured by an HMAC chain
`sig_i = HMAC(sig_{i-1}, link_i)` anchored at the verifier's root secret. Three
properties follow:

- **Offline attenuation.** Any holder can mint a narrower child (`attenuate`,
  or the verifier-checked `delegate`) because extending the chain only needs
  the parent's signature, not the root secret. This is real delegation, not
  central re-issuance (the named anti-pattern).
- **Cascading revocati

…

Try it

Open PR on GitHubView diff

Checkout locally

git fetch origin pull/70/head:pr-70
git checkout pr-70