Skip to content

Add common-jwt module to share JWT/JWK handling without per-guard jose4j shading #2155

Description

@jfallows

Is your feature request related to a problem? Please describe.

guard-jwt depends directly on org.bitbucket.b_c:jose4j and has to shade + relocate it itself: maven-shade-plugin includes org.bitbucket.b_c:jose4j in the artifactSet and relocates the org.jose4j package to io.aklivity.zilla.runtime.guard.jwt.internal.jose4j, and the JaCoCo config separately excludes org/jose4j/**/*.class from coverage instrumentation. This relocation is necessary so a private copy of jose4j bundled inside guard-jwt's jar can't collide on the classpath with a different jose4j version bundled by some other module.

That's three separate pieces of shade/coverage boilerplate (artifactSet include, relocation, JaCoCo exclude) that any other guard needing JWT/JWK validation (signature verification against a JWK, claims parsing, issuer/expiry checks) would have to duplicate verbatim, each shipping its own private, differently-namespaced copy of jose4j. There's no single place to bump the jose4j version, pick up a jose4j security patch, or fix a shared parsing/validation bug — every JWT-validating guard carries its own copy and its own shade config.

Describe the solution you'd like

Add a common-jwt module alongside the existing common-json, common-yaml, common-lang, common-avro, etc. modules under runtime/. It would:

  • Own the org.bitbucket.b_c:jose4j dependency once, performing the shade + relocation centrally instead of per-consumer.
  • Expose a small, clean internal API for the operations guards actually need: resolving a signing key from a JWK, verifying a JWS signature, and parsing/validating JWT claims (issuer, expiry, arbitrary claim extraction).
  • Let guard-jwt (and any future JWT-based guard) depend on common-jwt directly, dropping jose4j from its own compile classpath, its own shade-plugin relocation block, and its own JaCoCo exclusion for org/jose4j/**.

Describe alternatives you've considered

  • Status quo — keep shading + relocating jose4j independently in every JWT-validating guard. Works today, but duplicates the same shade-plugin config, JaCoCo exclusion, and a privately-relocated copy of jose4j in every module's jar, and means a jose4j version/security bump has to be repeated per module.
  • Depend on jose4j directly, unshaded, from each guard — simpler pom.xml, but reintroduces exactly the classpath-collision risk relocation exists to avoid if two guards bundling different jose4j versions ever end up loaded together.

Additional context

guard-jwt's actual jose4j usage is a fairly narrow, well-bounded surface — JsonWebKey (key resolution), JsonWebSignature (JWS verification), JwtClaims/NumericDate (claims + expiry), and InvalidJwtException/MalformedClaimException/JoseException for error handling — which seems like a reasonable starting API for common-jwt to wrap.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions