jwx

A complete, opinionated Go implementation of the JOSE stack: JWT, JWS, JWE, JWK, and JWA.

Library
Go
vv4.4.0
2,418stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
88/100Excellent
Development Activity96
Maintenance96
Community60
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
88/100Excellent
Architecture88
Code Quality90
Innovation88
Learning Curve85

jwx is a Go module implementing the full family of JOSE (Javascript Object Signing and Encryption) technologies: JWA, JWE, JWK, JWS, and JWT. Rather than shipping a minimal JWT-only helper, it covers the wider spec surface, including JWS messages with multiple signatures, detached and unencoded payloads, and JWE messages with multiple recipients, in both compact and JSON serialization forms.

The API follows a consistent, symmetric convention across packages, jws.Parse/Verify/Sign, jwe.Parse/Encrypt/Decrypt, jwt.Parse/Sign, with explicit required parameters and optional WithXXXX()-style functional options built on lestrrat-go/option. Most operations accept either a jwk.Key or a raw Go crypto key (*rsa.PrivateKey, *ecdsa.PrivateKey, etc.), so teams already holding standard-library key types are not forced through a conversion step.

Beyond the core RFCs, jwx has been extended to cover post-quantum primitives (ML-KEM, ML-DSA, HPKE) and ships an opt-in extension-module architecture, letting the core module stay lean while companion repositories under the jwx-go GitHub org add niche algorithms (ES256K, Ed448, JWKS caching, migration tooling) without bloating the main dependency tree.

What You Get

  • Full JWA/JWE/JWK/JWS/JWT coverage, not just a minimal JWT parser: multi-signature and multi-recipient JOSE messages, detached payloads, and RFC 7797 unencoded payloads
  • A uniform, opinionated API surface (Parse/Verify/Sign, Parse/Encrypt/Decrypt) with functional WithXXXX() options instead of ad-hoc config structs
  • Interoperability with both jwk.Key and raw standard-library crypto keys (*rsa.PrivateKey, *ecdsa.PrivateKey) across signing, verification, and encryption calls
  • Post-quantum cryptography support (ML-KEM, ML-DSA, HPKE) alongside classical RSA/ECDSA/EdDSA/HMAC algorithms
  • An opt-in extension-module system (companion repos for JWKS caching, ES256K, Ed448, migration helpers) that keeps the core module’s dependency footprint small
  • First-class HTTP integration via jwt.ParseRequest for pulling and verifying bearer tokens straight off an *http.Request
  • Bazel build support (BUILD.bazel, MODULE.bazel) alongside standard go build/go test workflows

Common Use Cases

  • Issuing and verifying signed JWT access/ID tokens for an API or auth server, including OpenID Connect claims via the jwt/openid subpackage
  • Encrypting sensitive payloads (not just tokens) with JWE for secure transport between services
  • Parsing and rotating JWKS (JSON Web Key Sets) fetched from an identity provider, with the jwkfetch companion module keeping a key set continuously up to date
  • Verifying bearer tokens directly from incoming HTTP requests in a middleware layer via jwt.ParseRequest
  • Building systems that need forward-looking, post-quantum-safe signing or key-encapsulation alongside today’s classical algorithms

Under The Hood

Architecture jwx is organized as one package per JOSE specification, jwa (algorithm identifiers), jwk (key representation and conversion), jws (signing/verification), jwe (encryption), and jwt (token building/parsing), each independently importable, with shared low-level machinery (base64 handling, a pluggable JSON codec, object pooling, key-type conversion) centralized under internal/. The top-level jwx.go file documents module-wide design decisions, such as staying buffer-oriented rather than adding true streaming support, showing the maintainers reason explicitly about API-wide tradeoffs rather than letting each package diverge. Extension algorithms (ES256K, Ed448, ML-KEM/ML-DSA/HPKE variants) live in separate companion repositories tracked via companions.yaml, keeping the core module’s own dependency graph small while still allowing the ecosystem to grow.

Tech Stack Built for Go 1.26+, jwx has adopted the still-experimental encoding/json/v2 API (gated behind GOEXPERIMENT=jsonv2 on 1.26, standard by 1.27), wrapped behind an internal JSON abstraction so the rest of the codebase isn’t coupled to a specific encoder. External dependencies are deliberately minimal: lestrrat-go/dsig and lestrrat-go/option from the same maintainer’s ecosystem, valyala/fastjson, and golang.org/x/crypto, with stretchr/testify reserved for tests. The project supports both standard go build and Bazel (MODULE.bazel, per-package BUILD.bazel files), and leans on code generation (go:generate directives driving jwxcodegen scripts and stringer) to keep accessors and option types consistent across packages instead of hand-maintaining boilerplate.

Code Quality Testing is extensive and layered: roughly 124 test files against about 190 non-test source files, including fuzz tests in multiple packages (fuzz_test.go in jwk, jws, jwx itself) backed by a dedicated fuzz.yml GitHub Actions workflow, plus benchmark tests, CodeQL static analysis, a separate lint workflow, a smoke-test workflow, and a companion-tests.yml workflow that verifies the extension modules still build against the core. Errors are handled through per-package errors.go files defining typed error values rather than bare string errors, and comment density in core files is high (100+ doc comments per file in jwt.go, jwk.go, jws.go), indicating the API surface is documented close to the code rather than only in external docs.

API Design The library’s defining choice is symmetry: every JOSE operation follows the same Parse/verb/WithXXXX()-option shape, so learning jws.Sign largely transfers to learning jwe.Encrypt or jwt.Sign. It ships a bundled Claude Code skill (jwx-dev-v4) specifically to help AI coding assistants pick the right algorithm and avoid common JOSE footguns, an unusually deliberate investment in developer experience for a cryptography library. A dedicated MIGRATION.md and versioned Changes-vN.md files give users a concrete upgrade path across the v2/v3/v4 major-version boundaries, which matters for a module whose import path changes on every semver-major bump under Go’s module versioning rules.

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