JWTParams.exp was typed str and filled with an ISO-8601 string, copied
verbatim into the reserved RFC 7519 exp claim. PyJWT requires exp to be a
NumericDate and raised DecodeError (subclass of PyJWTError), which the
blanket handler turned into 'Invalid JWT' — so every token minted with
--expires or expires_at failed auth. The module's own ISO comparison was
dead code because decode always failed first.
- JWTParams.exp: datetime | None; create_jwt unchanged (PyJWT converts)
- verify_jwt: drop the dead ISO comparison; catch jwt.ExpiredSignatureError
before PyJWTError so expired tokens report 'JWT expired'
- keys.py: pass expires_at through directly; drop unused format import
- generate_jwt.py: keep ISO string for display, datetime for the claim
- Tests: TestJWTExpiry (future/past/ISO-string/tampered) + rewritten
test_create_key_with_expires_at verifying minted keys both ways
Signed-off-by: ChethanUK <chethanuk@outlook.com>
* feat: add generate_jwt.py script for creating scoped JWTs
Adds a CLI utility script for generating Honcho JWTs without needing
to call the /v1/keys API endpoint. Useful for local development and
bootstrapping admin tokens.
Features:
- --admin flag for full-access tokens
- --workspace / --peer / --session flags for scoped tokens
- --expires flag with human-friendly duration syntax (e.g. 5h, 30d, 1y)
- --print-only flag for scripting (outputs bare token)
Examples:
uv run python scripts/generate_jwt.py --admin
uv run python scripts/generate_jwt.py --admin --expires 24h
uv run python scripts/generate_jwt.py --workspace my-ws --expires 30d
uv run python scripts/generate_jwt.py --workspace my-ws --peer my-peer --expires 1y
* docs: document generate_jwt.py in README auth setup section
* fix: remove t='' override to preserve utc_now_iso default in JWTParams
Per CodeRabbit review: explicitly setting t="" bypasses JWTParams's
default utc_now_iso timestamp, causing tokens for the same scope to
become byte-identical. Omitting t lets the default apply, ensuring
each generated token is unique.
* fix: address JWT script review feedback
* fix: type, lint
---------
Co-authored-by: Rajat Ahuja <rahuja445@gmail.com>