Skip to main content

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 beta software on the 0.6.x line; see the changelog for 0.2.0 breaking changes (exception hierarchy), 0.4.0 production-hardening, 0.5.0 performance notes, and 0.6.0 security/JWKS hardening.

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

Requires Python 3.10+. The wheel installs orjson as a runtime dependency (JSON serialization in the Python API layer).

For local development:

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

See RELEASING.md for maintainer release steps.

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 fairness: the default --competitor-key-mode pem keeps pre-parsed EncodingKey/DecodingKey for OxyJWT while competitors often receive PEM bytes (see Benchmarks). For asymmetric comparisons, also run with --competitor-key-mode cached.

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.

Contributing and security

See CONTRIBUTING.md for development setup and pull request expectations. Report security issues privately via SECURITY.md.

Performance benchmarks

OxyJWT is optimized for throughput on typical JWT workloads (especially HMAC). See docs-site/docs/benchmarks.md for smoke vs extended vs full workflows and key-preparation modes.

The table below is a historical snapshot (default script settings, pem competitor keys). RS256 encode numbers are not comparable to --competitor-key-mode cached; re-run the script on your hardware before drawing conclusions.

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 |

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oxyjwt-0.6.0.tar.gz (34.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

oxyjwt-0.6.0-cp310-abi3-win_amd64.whl (1.2 MB view details)

Uploaded CPython 3.10+Windows x86-64

oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (813.0 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

oxyjwt-0.6.0-cp310-abi3-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

oxyjwt-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl (1.5 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file oxyjwt-0.6.0.tar.gz.

File metadata

  • Download URL: oxyjwt-0.6.0.tar.gz
  • Upload date:
  • Size: 34.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for oxyjwt-0.6.0.tar.gz
Algorithm Hash digest
SHA256 6c6f5eb1d7f86ad77d2bbdc28f5f3eb8583f15babfecc992b0251207e9517471
MD5 a9ae08c06df6ed2ae3f88751fdfad23d
BLAKE2b-256 60b9eb149c790c59e6fb1bc81a2b5de1e66f9c0f36804c0957b774975e1af12f

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0.tar.gz:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxyjwt-0.6.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: oxyjwt-0.6.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for oxyjwt-0.6.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 285bef6118ce5418ecb5630f893c4fbbfa5929a07d8703315fc425c9aad82e61
MD5 693bd128b44bb4c1359bd32e80dc8d3d
BLAKE2b-256 34da7d8134c2ae9b0564e5c0d18f93f8321b15dc8863266ab184c376609e1a53

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0-cp310-abi3-win_amd64.whl:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 93742af9ca22acbd3957e4bcb4052152e2bf63ee0fabdf430393dc80058be7d5
MD5 b3b530a816ee150d81f94471fa5eccd9
BLAKE2b-256 86bdae6b61ecfb484dfd73afab51983e258949a4dc320d3bac25a8ee0fa5f287

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1b748bca889adbf57168a8a9d740b8ebd74cd605bb2d8c9ca6991a519962744a
MD5 8e3432608fb1825f523e79d2b6bb094e
BLAKE2b-256 2c967c959dd7e9db60580f274c7544d24ac3e39250448135c8efc6b375a2b393

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxyjwt-0.6.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for oxyjwt-0.6.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0b9256fcf3362b4b722b627c1ebc235dc55f373b22f68efe4d1a2e989187a47e
MD5 9025dc02732b04bdbdaf82d09191ee78
BLAKE2b-256 be39db9e1a3c5b03b4fcf4a4b4a9d6d017887d3090183bfa21834b622deaf071

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file oxyjwt-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for oxyjwt-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4c88d243d7a910ead99a62109a591af9c9c89a1cf5066464c648f9d124c8b8d6
MD5 45e3cbd7b964dab8f5e5af81628bc589
BLAKE2b-256 a55d8824e581813e3b9dbc55e3dca6ee8c4c4f6c945cc245b13ef1b1baea8cb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for oxyjwt-0.6.0-cp310-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on QueryaHub/OxyJWT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.7.0

6 files

This release

0.6.0 This release

6 files

0.5.0

6 files

0.4.0

6 files

0.3.0

6 files

0.2.0

6 files

0.1.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page