Skip to content

QueryaHub/OxyJWT

Repository files navigation

OxyJWT

OxyJWT is a Python JWT/JWS library backed by a Rust core. The public API follows PyJWT for encode, decode, decode_complete, JWK/JWKS helpers, and the PyJWKClient. When signature verification is enabled (the default), you must pass an algorithms allow-list, matching common PyJWT usage. Unverified decode is available only when you explicitly set options["verify_signature"] to False (treat the payload as untrusted).

This project is still alpha software; see the changelog for 0.2.0 breaking changes (exception hierarchy).

Documentation

The full documentation is written with MkDocs and lives in docs-site/ as a standalone site:

Build it locally with:

python -m venv .venv
.venv/bin/python -m pip install -U -r docs-site/requirements.txt
.venv/bin/mkdocs serve -f docs-site/mkdocs.yml

Or build a static documentation image for deployment:

docker compose -f docs-site/docker-compose.yml up -d --build

The static site is served on http://127.0.0.1:8001 by default. Point your own reverse proxy at that upstream for HTTPS. Details and OXYJWT_DOCS_PORT are in docs-site/README.md.

Installation

pip install oxyjwt

For local development:

python -m venv .venv
.venv/bin/python -m pip install -U pip maturin pytest cryptography pyjwt
.venv/bin/maturin develop --release
.venv/bin/python -m pytest

HMAC Example

import time

import oxyjwt

secret = "super-secret"
payload = {
    "sub": "user-123",
    "role": "admin",
    "aud": "api",
    "iss": "auth-service",
    "exp": int(time.time()) + 3600,
}

token = oxyjwt.encode(payload, secret, algorithm="HS256", headers={"kid": "key-1"})
claims = oxyjwt.decode(
    token,
    secret,
    algorithms=["HS256"],
    audience="api",
    issuer="auth-service",
)

Asymmetric Keys

Use explicit key constructors for RSA, PSS, ECDSA, and EdDSA:

import oxyjwt

signing_key = oxyjwt.EncodingKey.from_rsa_pem(private_pem)
verification_key = oxyjwt.DecodingKey.from_rsa_pem(public_pem)

token = oxyjwt.encode({"sub": "user-123", "exp": 1893456000}, signing_key, algorithm="RS256")
claims = oxyjwt.decode(token, verification_key, algorithms=["RS256"])

Supported algorithms in v1:

  • HS256, HS384, HS512
  • RS256, RS384, RS512
  • PS256, PS384, PS512
  • ES256, ES384
  • EdDSA

Exceptions

OxyJWT exposes a stable exception hierarchy:

try:
    claims = oxyjwt.decode(token, key, algorithms=["HS256"])
except oxyjwt.ExpiredSignatureError:
    ...
except oxyjwt.InvalidTokenError:
    ...

All package exceptions inherit from oxyjwt.OxyJWTError.

Benchmarks

There is a small comparison script for OxyJWT, PyJWT, python-jose, and Authlib:

python -m venv .venv
.venv/bin/python -m pip install -U pip maturin ".[bench]"
.venv/bin/maturin develop --release
.venv/bin/python scripts/compare_jwt_libraries.py \
  --algorithms all \
  --iterations 1000 \
  --rounds 3 \
  --warmup 100 \
  --json benchmark-results/all-algorithms.bench.json \
  --markdown benchmark-results/all-algorithms.bench.md

The script covers HMAC, RSA, RSA-PSS, ECDSA, and EdDSA algorithms. Unsupported library/algorithm combinations are reported as 0 throughput. For a quicker smoke test, pass something like --algorithms HS256,RS256,EdDSA --iterations 100 --rounds 1.

Benchmark outputs are ignored by git because results depend on the machine, Python version, compiler flags, and CPU state.

The default Rust crypto backend is aws_lc_rs, chosen for stronger performance on RSA and ECDSA in local benchmarks. You can still build with rust_crypto for comparison:

PYO3_BUILD_EXTENSION_MODULE=1 maturin build --release --no-default-features --features rust_crypto

Security Notes

  • Always pass a fixed server-side algorithms list to decode.
  • Never build the algorithms list from untrusted token headers.
  • alg="none" is intentionally unsupported.
  • Raw str/bytes keys are accepted only for HMAC algorithms. Use EncodingKey.from_* and DecodingKey.from_* for RSA, PSS, ECDSA, and EdDSA.
  • Validate audience and issuer for application tokens when those claims are part of your trust model.
  • decode_unverified and get_unverified_header do not authenticate a token. Use them only for inspection/debugging flows, never for authorization.

OxyJWT implements JWT/JWS signing and verification. JWE encryption is not part of the first version.

🚀 Performance Benchmarks

OxyJWT is built for absolute speed. By bypassing the Python GIL and leveraging Rust's cryptographic primitives, it completely destroys standard Python libraries in both symmetric and asymmetric cryptography.

Below is a performance comparison measured in Operations per second (ops/sec) (higher is better):

Algorithm Operation ⚡ OxyJWT PyJWT Authlib python-jose
HS256 Encode 620,270 140,670 99,408 99,507
HS256 Decode 361,073 109,272 94,823 51,838
RS256 Encode 1,934 35 35 35
RS256 Decode 58,752 27,200 26,085 23,046
EdDSA Encode 69,105 17,518 15,014 N/A
EdDSA Decode 31,666 10,741 10,317 N/A
ES256 Encode 46,559 19,632 16,199 19,723

Tested against standard Python ecosystem libraries. OxyJWT consistently dominates across all algorithms.

About

⚡ Blazing-fast Python JWT library written in Rust. Bypasses the GIL for high-performance cryptography.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors