Skip to content

Modernize JWT verification and crypto backend - #39

Merged
quinnj merged 16 commits into
masterfrom
codex/production-grade-jwt-verifier
Jun 30, 2026
Merged

Modernize JWT verification and crypto backend#39
quinnj merged 16 commits into
masterfrom
codex/production-grade-jwt-verifier

Conversation

@quinnj

@quinnj quinnj commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

  • Replaces the MbedTLS crypto backend with direct OpenSSL_jll/SHA-backed signing and verification.
  • Adds modern JOSE algorithm support for PS*, ES*, and EdDSA/Ed25519, including RSA, EC, OKP, and octet JWK parsing.
  • Adds a provider-neutral Verifier / VerifiedJWT API with explicit algorithm allowlists, registered claim validation, structured verifier errors, cached remote JWKS, and OIDC discovery.
  • Refreshes README guidance, migration notes, and CI, and removes live-network dependency from the test suite.

Security And Compatibility Notes

  • The new verifier requires an explicit accepted-algorithm list and validates exp, nbf, iat, iss, aud, sub, jti, nonce, required claims, leeway, and max token age.
  • Legacy validate! and with_valid_jwt remain available as lower-level signature validation helpers, but application code should prefer verify(::Verifier, ...).
  • JWT token parts are read-only through the public API so validation state cannot be reused across key or policy changes.
  • The Julia compat floor is raised to 1.6 to support the OpenSSL_jll-backed backend.

Validation

  • julia --project=. --startup-file=no -e 'using Pkg; Pkg.test()' passed locally with 2038 tests.
  • git diff --check passed for each committed item.
  • Workflow YAML parsed locally with Ruby's YAML parser.

Co-authored by Codex

@quinnj
quinnj marked this pull request as ready for review June 30, 2026 03:41
@quinnj
quinnj force-pushed the codex/production-grade-jwt-verifier branch from 62878c7 to 68980d1 Compare June 30, 2026 04:37
quinnj and others added 6 commits June 30, 2026 06:51
…eanup

Security & correctness:
- crypto: GC.@preserve the EVP_PKEY across the DigestSign/Verify Init/Update/Final
  sequence so a non-retained key cannot be finalized mid-operation (use-after-free).
  Rename sign_rsa/verify_rsa to evp_digest_sign/evp_digest_verify (they also serve
  EC/OKP via the shared EVP path).
- verifier: verify() now raises typed JWTVerificationError/JWTClaimError instead of a
  bare ArgumentError on a malformed header/payload, matching the documented taxonomy.
  A missing expected iss/sub/jti/nonce/aud now reports :claim_missing, not :claim_type.
- remote JWKS: require the OIDC discovery `issuer` field (no longer defaulted to the
  configured issuer), require an http(s) `jwks_uri`, and reject symmetric ("oct") keys
  arriving from a remote endpoint.
- fetch_url: reject non-2xx HTTP responses (Downloads.request does not throw on them),
  so an error page can no longer be parsed into the keyset cache.
- base64url_decode: strict base64url - reject +/ , mid-string '=', length % 4 == 1, and
  non-canonical trailing bits. The rsa/oct test JWKS fixtures are converted from standard
  base64 to base64url (identical decoded key bytes).
- JWKSet: guard the resolve/refresh path with a lock for concurrently shared verifiers.
- exp stays optional by default (unchanged); document that leeway widens max_age.

Cleanup:
- remove ACTION_ITEMS.md (internal agent roadmap with local paths).
- drop dead urlenc/urldec/padb64 and the now-unused Base64 dependency.
- README signing example uses string(jwt) (String(jwt) was a MethodError).

Adds regression tests. Full suite (2657 tests) and the JuliaC --trim=safe compile pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@quinnj
quinnj merged commit a89339f into master Jun 30, 2026
10 checks passed
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