python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt
python3 poc_webapp.py # open http://localhost:8090Click: Log in as Alice → GET /orders (allowed; watch the token's cnf
fingerprint match the proof's key fingerprint). Then the attack buttons: Steal
token (fingerprints mismatch → deny), Tamper, Replay on replica B
(shared store blocks it fleet-wide), Revoke. The center panel shows exactly
what's on the wire; the right panel shows each resource-server decision.
Honest demo framing: this is DPoP (RFC 9449) + revocation built on Ed25519 +
SHA-256. It does not invent new crypto — it composes standard primitives
correctly so a stolen token is useless without the client's key. That is the
defensible claim. See THREAT_MODEL.md and JWT_POP_ADDON_SPEC.md.
Makes your existing JWTs sender-constrained: a token is bound to a client-held key, and every request carries a fresh proof signed by that key. A stolen token alone becomes useless — the thief doesn't have the key. It is purely additive: the access token stays an ordinary signed JWT, so legacy validators keep working (verified below).
Built on standardized, vetted primitives — Ed25519 (RFC 8032), SHA-256 + JWK thumbprints (RFC 7638), JWT/JWS (RFC 7519/7515),
cnfbinding (RFC 7800), DPoP-style proofs (RFC 9449), optional JWE (RFC 7516). It is, honestly, a DPoP profile with revocation bundled in — and that reuse is the point. There is no roll-your-own crypto here, because for something that strengthens real JWTs, that's the correct call. Full rationale and threat model inJWT_POP_ADDON_SPEC.md.
| File | What it is |
|---|---|
jwt_pop.py |
Reference implementation: AuthServer, Client, ResourceServer, revocation |
jwt_pop_demo.py |
Legit flow + 8 attack scenarios, all blocked |
JWT_POP_ADDON_SPEC.md |
Standards-style design: threat model, wire formats, verification rules, security considerations |
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install -r requirements.txt
python3 jwt_pop_demo.pyOr in VS Code: open the folder, select the .venv interpreter, hit ▶ on
jwt_pop_demo.py (a launch config is included).
- Legitimate request: ALLOW
- Stolen token + attacker's own key → DENY (
proof_key_not_bound_to_token) - Stolen token + replayed proof → DENY (
proof_replayed) - Valid proof, wrong URL / wrong method → DENY (
uri_mismatch/method_mismatch) - Tampered access token → DENY (
bad_access_token_signature) - Revoked token → DENY (
token_revoked) - Expired token → DENY (
token_expired) - Reused server nonce → DENY (
bad_or_missing_nonce)
Interop check (in the spec/demo notes): the standard PyJWT library validates
the bound token as a normal JWT and ignores the extra cnf claim — proving the
addon doesn't break existing JWT.
It raises the bar dramatically: token theft alone no longer grants access,
replay is bounded, revocation is near-real-time, and claims can be encrypted.
It does not make you invulnerable — if the client's private key is stolen
(malware with enclave access), or a live malicious proxy relays the user's own
fresh proofs, the attacker regains power. Keep PoP keys non-extractable
(TPM/enclave/WebCrypto), keep TTLs short, and enforce all ten verification steps
in JWT_POP_ADDON_SPEC.md §5.