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 #52Auth

varuni7: delegatable capability tokens with cascading, partition-tolerant revocation

Problem 4 (auth). The default jwt plugin cannot delegate a subset of a

Author

Status
In review
Opened on
Jul 1
Branch
hackathon/varuni7-delegatable-auth

Description

The pitch.

# [Hackathon] varuni7: delegatable capability tokens with cascading, partition-tolerant revocation

**Problem 4 (auth).** The default `jwt` plugin cannot delegate a subset of a
capability, and revokes by exact token string with no parent/child relationship.
This ships `delegatable`: macaroon-style tokens where a holder mints a strictly
narrower, shorter-lived sub-token for another agent **offline** (no issuer
round-trip), and revoking a token severs its entire subtree.

## Design

- **Macaroon HMAC chain.** A child seal is `HMAC(parent_seal, caveat)`, so a
  holder can only *add* restrictions (subset scopes, shorter TTL, bound
  audience) — never widen them. `delegate()` also checks the scope subset and
  clamps child TTL ≤ parent.
- **Cascade by construction.** Revocation is keyed on the seal, not the token
  string. `verify()` recomputes the chain, and a revoked ancestor seal severs
  every descendant — no per-child revocation list.
- **Partition-tolerant revocation.** Revocation state is a grow-only set
  (G-Set CRDT). `merge` is the set union — commutative, associative,
  idempotent — so replicas converge by gossip regardless of order, duplication,
  or loss. Safety is monotone (a seal once observed revoked is never accepted
  again), and a verifier that has not yet heard a revocation still accepts until
  it merges one.
- **Determinism.** No `uuid`, no `time.time()`. Token identity is the seal (a
  pure function of content + secret); all time comes from an injected clock.
  Same seed → byte-identical trace.

## Attacks defeated (adversarial validator)

The `delegated_auth` scenario + validators PASS on `delegatable` and FAIL on
`jwt`. Three attack classes are blocked, each a typed error:

1. **Scope escalation** — child requests a scope the parent lacks → `ScopeEscalationError`.
2. **Stale / revoked parent** — delegate or verify through a revoked ancestor → `RevokedAncestorError`.
3. **Audience confusion** — token presented by an agent that is not its audience → `AudienceMismatchError`.

Plus a **convergence** check: after the revoked seal is gossiped, the revoked
intermediary can no longer mint tokens while its siblings still can — proof the
revocation propagated via CRDT merge, not just on the coordinator.

## Verify it

```bash
uv sync
nest run scenarios/delegated_auth.yaml -o traces/delegated_auth.jsonl
python -c "
from pathlib import Path
from nest_core.validators import validate_trace
for r in validate_trace(Path('traces/delegated_auth.jsonl'), 'delegated_auth'):
    print(('PASS' if r.passed else 'FAIL'), r.name, '-', r.detail)
"
# Swap `auth: delegatable` -> `auth: jwt` in the YAML and the same four validators FAIL.
```

## Tests

- 51 new tests: example-based + `hypothesis` property tests (scope-subset,
  cascade over random chains, CRDT merge laws, determinism) + the 3 attacks +
  partition convergence, for both the plugin and the validators.
- Full suite: **592 passed, 1 skipped**. `make ci-local`: all 5 checks pass
  (`ruff`, `ruff format`, `pyright` strict, `pytest`).

## Files

- `packages/nest-plugins-reference/nest_plugins_reference/auth/delegatable.py` — plugin
- registered in `plugins.py` `_BUILTINS` **and** `nest-plugins-reference/pyproject.toml` entry point
- `packages/nest-core/nest_core/scenarios_builtin/delegated_auth.py` + `scenarios/delegated_auth.yaml`
- 4 validators in `nest_core/validators.py`
- `docs/layers/auth.md`
- tests: `test_delegatable_auth.py`, `test_delegated_auth_scenario.py`

— with Claude Code

Try it

Open PR on GitHubView diff

Checkout locally

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