Skip to content

Add generic JWK/JWKS-from-JSON importer - #1

Merged
tannevaled merged 1 commit into
mainfrom
feat/jwks-import
Jul 3, 2026
Merged

Add generic JWK/JWKS-from-JSON importer#1
tannevaled merged 1 commit into
mainfrom
feat/jwks-import

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Summary

Adds a generic, protocol-agnostic JWK/JWKS-from-JSON importer to the library — the import counterpart of the existing NewJWK/Export path. Any JWS consumer (not just OIDC) can now turn a provider's key set into verification keys.

The logic is upstreamed from go-ruby-oidc/oidc, which carried an OIDC-specific KeySet/ParseJWKS that is really generic JWT infrastructure. Only the reusable core moves here; issuer/audience/nonce/HTTP-cache logic stays in oidc.

API added

  • ParseJWK(data []byte) (*JWK, error) — parse a single JWK, materialising its RSA (n/e) or EC (crv/x/y) public key. An unsupported key type is an error.
  • ParseJWKS(data []byte) (*JWKS, error) — parse a {"keys":[...]} set; RSA/EC keys are materialised and keyed by the provider kid, a key type the library cannot use for JWS (e.g. oct) is skipped.
  • (*JWKS) Select(kid, alg string) (*JWK, error) — resolve a key by kid; for a kid-less token fall back to the sole signing-capable key whose type serves alg (rejecting an ambiguous/empty set).
  • JWK.Alg / JWK.Use fields (populated by the importers) and the ErrJWK sentinel (the gem's JWT::JWKError, a DecodeError).

Decode's kid-resolution now routes through Select, so a kid-less single-key JWKS also verifies.

Endianness

Import is endian-safe: every field is base64url text decoded byte-wise and read big-endian by math/big.Int.SetBytes, both byte-order independent. Exercised by the existing s390x (big-endian) qemu CI lane.

Tests

  • Golden selection: fixed JWKS JSON -> correct key by kid; wrong-kid cross-verification fails.
  • Malformed JSON / bad key material / unsupported kty / unsupported curve -> ErrJWK.
  • Select kid hit/miss, kid-less sole/ambiguous/no-candidate/enc-use arms.
  • 100% coverage retained, -race clean, builds on all six 64-bit arches + darwin/windows.

🤖 Generated with Claude Code

Add ParseJWK and ParseJWKS: read a single JWK or a JWKS ({"keys":[...]})
from JSON and materialise each RSA (n/e) or EC (crv/x/y) entry into a
usable crypto public key, keyed by the provider-assigned "kid" and
selectable by kid/alg/kty/use. This is the import half of the gem's
JWT::JWK, complementing the existing NewJWK/Export path.

The importer is transport- and protocol-agnostic (no issuer/audience/
nonce logic), so any JWS consumer can turn a provider's key set into
verification keys. JWKS.Select resolves a key by kid, falling back for a
kid-less token to the sole signing-capable key whose type serves the
header alg; the Decode kid-resolution path now routes through it so a
kid-less single-key set also verifies.

Import is endian-safe: fields are base64url text decoded byte-wise and
read big-endian by math/big.Int.SetBytes, both byte-order independent
(verified by the s390x qemu CI lane).

Add ErrJWK (the gem's JWT::JWKError, a DecodeError) for malformed JWK,
bad key material, and unsupported key type/curve.

100% coverage retained; -race clean; builds on all six 64-bit arches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 8781efb into main Jul 3, 2026
9 checks passed
@tannevaled
tannevaled deleted the feat/jwks-import branch July 3, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant