JWT Walkthrough
The hero 'wow gap' demo: ~50 lines of spec, 100+ lines of correct JWT code.
This is the Jaunt story in one page: a readable spec stub becomes a pile of boring correctness work — strict parsing, HMAC verification, expiry checks, and runnable tests.
Running this guide calls the OpenAI API and will spend tokens. Make sure OPENAI_API_KEY is set.
What We're Building
A minimal HS256 JWT implementation from a single spec file:
- A
Claimsmodel (Pydantic) create_token(user_id, secret, ttl=...) -> strverify_token(token, secret) -> Claimsrotate_token(token, secret, ttl=...) -> str
The Spec
Full file: examples/jwt_auth/src/jwt_demo/specs.py
"""JWT Authentication — Jaunt Example"""
from __future__ import annotations
from datetime import timedelta
import jaunt
from pydantic import BaseModel
class Claims(BaseModel):
"""Decoded token payload."""
sub: str # subject (user id)
iat: float # issued-at (unix timestamp)
exp: float # expiry (unix timestamp)
@jaunt.magic()
def create_token(
user_id: str, secret: str, *, ttl: timedelta = timedelta(hours=1)
) -> str:
"""
Create an HS256-signed JWT.
Structure: base64url(header) . base64url(payload) . base64url(signature)
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": user_id, "iat": <now>, "exp": <now + ttl>}
- Use HMAC-SHA256 with `secret` as the key.
- base64url encoding must omit padding ("=" characters).
- Raise ValueError if user_id is empty.
"""
raise RuntimeError("spec stub (generated at build time)")
@jaunt.magic(deps=[create_token, Claims])
def verify_token(token: str, secret: str) -> Claims:
"""
Verify an HS256-signed JWT and return its claims.
Steps:
1. Split token on "." — must have exactly 3 parts.
2. Recompute HMAC-SHA256 over header.payload; compare to signature.
3. Decode payload JSON into Claims.
4. Check exp > current time.
Errors:
- Raise ValueError("malformed") if structure is wrong.
- Raise ValueError("invalid signature") if HMAC doesn't match.
- Raise ValueError("expired") if token has expired.
"""
raise RuntimeError("spec stub (generated at build time)")
@jaunt.magic(deps=[create_token, verify_token])
def rotate_token(
token: str, secret: str, *, ttl: timedelta = timedelta(hours=1)
) -> str:
"""
Verify an existing token and issue a fresh one for the same subject.
- Verify the old token (propagate any errors).
- Create a new token with the same user_id and a fresh ttl.
- The rotated token MUST have strictly increasing iat/exp.
"""
raise RuntimeError("spec stub (generated at build time)")That's the entire spec. ~50 lines of intent, zero implementation logic.
Run The Build
From the repo root:
uv sync
export OPENAI_API_KEY=...
uv run jaunt build --root examples/jwt_authJaunt writes the generated implementation to:
examples/jwt_auth/src/jwt_demo/__generated__/specs.pyLook At The Output
You wrote ~50 lines of spec. Jaunt generated 100+ lines of correct, edge-case-handling code. Here are excerpts:
Base64url helper (no padding):
def _b64url_encode_no_pad(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")JWT assembly with canonical JSON:
header_json = json.dumps(header_obj, separators=(",", ":"), sort_keys=True).encode("utf-8")
payload_json = json.dumps(payload_obj, separators=(",", ":"), sort_keys=True).encode("utf-8")
header_b64 = _b64url_encode_no_pad(header_json)
payload_b64 = _b64url_encode_no_pad(payload_json)
signing_input = f"{header_b64}.{payload_b64}"
sig = hmac.new(secret.encode("utf-8"), signing_input.encode("utf-8"), hashlib.sha256).digest()
sig_b64 = _b64url_encode_no_pad(sig)
return f"{signing_input}.{sig_b64}"Signature verification and expiry checks:
# Recompute HMAC and compare
expected_sig = hmac.new(
secret.encode("utf-8"), signing_input.encode("utf-8"), hashlib.sha256
).digest()
if not hmac.compare_digest(actual_sig, expected_sig):
raise ValueError("invalid signature")
# Check expiry
if payload["exp"] <= time.time():
raise ValueError("expired")All the boring-but-critical stuff: padding removal, constant-time comparison, JSON canonicalization, expiry enforcement. You specified what; Jaunt did how.
Generate And Run Tests
PYTHONPATH=examples/jwt_auth/src uv run jaunt test --root examples/jwt_authJaunt writes generated tests to examples/jwt_auth/tests/__generated__/specs.py.
Example generated test excerpt:
def test_roundtrip_create_and_verify() -> None:
api = _load_api()
token = api.create_token("user-42", "s3cret")
claims = api.verify_token(token, "s3cret")
assert getattr(claims, "sub") == "user-42"
assert getattr(claims, "exp") > getattr(claims, "iat")The Skills Bonus
Because the spec imports pydantic, Jaunt auto-generates a PyPI skill at build time:
examples/jwt_auth/.agents/skills/pydantic/SKILL.mdThis gives the LLM concrete Pydantic usage patterns, improving the quality of generated code that uses external libraries.
See: Auto-Generated PyPI Skills.
Next: Adding Jaunt To Your Project.