jwt-simple

A fast, safe-by-default Rust library for creating and verifying JWT and JWE tokens across every major signing and encryption algorithm.

Library
Cargo
v0.13.1
280stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
71/100Good
Development Activity88
Maintenance64
Community52
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture85
Code Quality78
Innovation88
Learning Curve62

jwt-simple is a Rust crate for working with JSON Web Tokens (JWT) and JSON Web Encryption (JWE) without the common pitfalls that plague hand-rolled JWT code. It covers the full spread of algorithms used in the wild — HMAC (HS256/384/512), RSA (RS*/PS*), ECDSA (ES256/ES384/ES256K), EdDSA, and even post-quantum ML-DSA (FIPS 204) — plus JWE key management via RSA-OAEP, AES Key Wrap, and ECDH-ES with AES-GCM content encryption. An experimental CWT (CBOR-encoded token) mode is also included behind a feature flag.

The library leans hard into secure defaults: signature verification, expiration, and standard claims validation all happen automatically inside verify_token, rather than being left to the caller to remember. It compiles cleanly to WebAssembly/WASI out of the box (including Fastly Compute), and on WASI runtimes that expose the WASI-Crypto interface it can offload RSA and AES-GCM operations to the host for order-of-magnitude speed and side-channel improvements over pure-Rust WASM crypto. A pure-rust feature flag also sidesteps boring/BoringSSL entirely for portability-constrained targets.

What You Get

  • Symmetric (HMAC) and asymmetric (RSA, ECDSA, EdDSA, post-quantum ML-DSA) signing and verification, all behind one consistent authenticate/verify_token API
  • JWE support for encrypted tokens with RSA-OAEP, AES Key Wrap, and ECDH-ES key agreement plus AES-GCM content encryption
  • Automatic verification of expiration, not-before, issuer, audience, and other standard claims — no manual claim-checking required
  • Configurable VerificationOptions for clock tolerance, required key IDs, nonce replay protection, and maximum token age/length
  • First-class WebAssembly/WASI support, including optional WASI-Crypto host offload for hardware-accelerated RSA and AES-GCM
  • A pure-rust feature flag to drop the boring (BoringSSL) dependency entirely for constrained build targets

Common Use Cases

  • Issuing and validating access tokens for a Rust API server (HS256/ES256 authentication and signature flows)
  • Interoperating with third-party identity providers (Auth0, Okta) that expect specific JWT algorithms
  • Encrypting sensitive claims in transit with JWE rather than relying on transport-layer confidentiality alone
  • Running JWT verification inside a WebAssembly/WASI function-as-a-service environment (e.g. Fastly Compute)
  • Preparing for post-quantum migration by issuing ML-DSA-signed tokens alongside classical algorithms

Under The Hood

Architecture The crate is organized around a generic token core (token.rs) that handles compact JWT encoding/decoding, header construction, and claim serialization independent of the signing algorithm, with each algorithm (algorithms/hmac.rs, rsa.rs, es256.rs, es384.rs, es256k.rs, eddsa.rs, mldsa.rs) implementing a shared key-pair/signing trait and re-exported from algorithms/mod.rs. JWE support lives in its own jwe_token.rs plus an algorithms/jwe/ submodule split into content encryption, ECDH-ES, RSA-OAEP, and AES key-wrap implementations, and an experimental CWT (CBOR token) path is mirrored separately in cwt_token.rs rather than sharing the JWT encoder. Claims handling (claims.rs, over 1,100 lines) centralizes custom-duration parsing, standard-claim validation, and generic custom-claim support via serde, so verification logic is written once and reused across every algorithm rather than duplicated per key type.

Tech Stack Built on Rust 2018/edition with a 1.85 MSRV, the crate composes RustCrypto elliptic-curve implementations (p256, p384, k256) with ed25519-compact for EdDSA, dedicated hmac-sha1/256/512-compact crates for HMAC, ciborium for optional CBOR/CWT support, and serde/serde_json for claim serialization. For RSA and AES-GCM it defaults to the boring (BoringSSL bindings) crate for performance via the optimal feature, falling back to the pure-Rust superboring crate on WASM targets or when pure-rust is selected — with an additional wasi-crypto feature that hands RSA and AES-GCM off to a WASI host implementation. thiserror and anyhow provide the error types, and zeroize clears secret key material from memory.

Code Quality Unit tests are present across the core modules (claims.rs, token.rs, jwe_token.rs, cwt_token.rs), and a GitHub Actions workflow (ci.yml) runs the Rust test suite on every push. Errors are modeled as a single typed JWTError enum (over 40 explicit variants covering everything from clock drift to JWE key-unwrap failures) via thiserror, rather than being collapsed into generic strings, and the top-level Error alias reuses anyhow for ergonomic ?-based propagation at the call site. There is no separate tests/ integration directory or visible linter/formatter config beyond the CI workflow itself.

API Design The public surface favors minimal boilerplate: HS256Key::generate(), key.authenticate(claims)?, and key.verify_token::<NoCustomClaims>(&token, options)? cover the common path in three lines, with VerificationOptions and HeaderOptions structs available for power users who need issuer/audience/nonce/replay controls without changing the basic call shape. The README and inline rustdoc comments (duplicated so both surfaces stay current) document every algorithm and option with runnable examples, and the crate’s explicit inclusion of post-quantum ML-DSA algorithms alongside classical ones is notably ahead of most JWT crates in the ecosystem.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search