OxyRoute can validate Bearer JWTs in the Rust layer for routes you mark as protected. The implementation uses the jsonwebtoken crate: you pass an allow-list of algorithm names and jwt_secret text whose interpretation depends on the algorithm family.
- HMAC (symmetric):
HS256,HS384,HS512—jwt_secretis the shared secret (raw bytes of the string). - RSA:
RS256,RS384,RS512,PS256,PS384,PS512—jwt_secretmust be a PEM-encoded public key (or certificate PEM) for verification. - ECDSA:
ES256,ES384—jwt_secretis a PEM-encoded public key for the curve. - EdDSA:
EdDSA—jwt_secretis PEM for the public key.
Only one family (HMAC vs RSA vs EC vs Ed) may appear in algorithms for a given route. Unsupported or unknown names are rejected at route registration when algorithms is parsed from Python.
The HTTP verb decorators on App accept:
require_jwt: bool— if true, a valid JWT and successful verification are required before the handler runs (see below)jwt_cookie: str | None— if set, and there is no usableAuthorization: Bearervalue, the token is read from theCookieheader: the first non-emptyname=<value>pair wherenamematches this string (case-sensitive).Bearerstill wins when both are presentjwt_secret: str | None— whenrequire_jwtis set: HMAC secret, or asymmetric public key PEM (see above)algorithms: list[str] | None— e.g.["HS256"]or["RS256"](defaults in code to["HS256"]if the list is omitted or empty is normalized to HMAC-256)jwt_issuer: str | None— if set, theissclaim must match (viajsonwebtokenvalidation)jwt_audience: str | None— if set, theaudclaim is validated against this value. If omitted, audience checking is disabled for that route (so tokens with anaudclaim are not rejected for audience mismatch; opt in by passingjwt_audience)jwt_leeway: int | None— clock skew in seconds forexp/nbf(default when omitted: 60, matching thejsonwebtokencrate default)
If require_jwt is set, jwt_secret is required and must match the chosen algorithms (e.g. PEM for RS256). Registration fails with a clear error if the key cannot be loaded or the family does not match.
The handler is not executed when:
- The route requires JWT but
jwt_secretis missing - The
Authorizationheader is not a usable Bearer token and there is nojwt_cookievalue, or the named cookie is missing/empty; otherwise cookie-based token is used whenjwt_cookieis set - The token does not verify (including wrong algorithm/secret) — typically 401 with a plain
Unauthorizedbody - The token is expired in a way the library classifies as signature expiry — 401 with body
Expiredin the current implementation
The native module exports decode_jwt_hs(token, key, algorithm_list), re-exported from the top-level oxyroute package. It decodes a token and returns claims, HMAC (HS*) only, for golden tests against the oxyjwt package. For RSA/EC/Ed verification in Python tests, use your usual stack (e.g. PyJWT + cryptography with the same PEM keys).
Optional dev dependencies: oxyjwt, pyjwt, and cryptography are in oxyroute[dev] for tests; production only needs the native extension and your jwt_secret / algorithms configuration.
- Handlers —
claimsin kwargs - Installation —
oxyroute[dev]