The official MicroProfile JWT 2.2 TCK verifies that an implementation correctly accepts, rejects and exposes a wide range of forged tokens against an Arquillian reference application — inline keys, JWKS, JWE, standard claims, MP claims, Authorization and cookie transport, key rotation, falsified signatures, exp / nbf / iat at the boundaries. Cervantes passes it at 208 / 208 NEW (MicroProfile JWT Auth 2.2 TCK, run on 2026-10-04). The 2.1 release was passed at 206 / 206 (May 2026, milestone M6); the 2.2 suite adds RsaAndEcSignatureAlgorithmTest (2 tests: RS256 and ES256 tokens verified against one mixed RSA+EC JWKS) and drops the EJB, JACC and Servlet container tests.
Status
| Metric | Value |
|---|---|
Tests executed |
208 |
Passed |
208 ✅ |
Failed |
0 |
Errors |
0 |
Skipped |
0 |
Any future regression must be logged in the repository’s TCK.md with: test name, reason, remediation plan.
Prerequisites
The org.eclipse.microprofile.jwt:microprofile-jwt-auth-tck:2.2 artefact (and its tests classifier) is now available on Maven Central — it is downloaded automatically. The runner also installs cassini-tck into the local M2 to provide CassiniTestHarness.
sdk env # Java 25 + Maven 3.9.16
./mvnw -ntp install -DskipTests # installs cervantes-core, cervantes-jaxrs, cervantes-cdi-vauban, …
Runner execution
The run-official-tck-mp-jwt-2.2.sh script at the repository root drives every variant.
# Smoke — single fast test to validate the installation
./run-official-tck-mp-jwt-2.2.sh
# Full suite — equivalent to the official 208-test TCK
./run-official-tck-mp-jwt-2.2.sh all
# Targeted test via -Dtest=
./run-official-tck-mp-jwt-2.2.sh -Dtest=PublicKeyAsPEMTest
The runner uses Arquillian. The Surefire report lands in cervantes-tck/target/surefire-reports/.
Runner architecture
cervantes-tck is in-reactor behind the tck Maven profile of cervantes-parent (TCK harmonisation, vidocq-runtime-tck-* pattern): a plain mvn install never builds nor downloads it. Direct invocation: ./mvnw -P"tck,smoke" -pl cervantes-tck test (smoke) or ./mvnw -P"tck,tck-official" -pl cervantes-tck test (full suite). Template originally mirrored from heisenberg-tck.
|
The runner was historically detached from the reactor (standalone |
Stack assembled by the runner:
| Layer | Component |
|---|---|
Spec |
|
MP JWT implementation |
|
CDI container |
Vauban ( |
Arquillian container |
|
HTTP transport |
Chappe ( |
Test framework |
TestNG ( |
Documented exclusions
One exclusion, not applicable to the Core + JWT profile targeted by Cervantes:
| Exclusion | Justification |
|---|---|
|
TestNG group for group-to-role mapping via the Jakarta EE Security API — marked optional by the spec, not required for MP JWT 2.2 conformance, and not implemented. |
The MP JWT 2.2 tests jar no longer ships the EJB, JACC and Servlet container tests. The 2.1 runner excluded those three packages by path, and the exclusions were removed from cervantes-tck/pom.xml with the bump to 2.2.
The exclusion is declared in the Surefire configuration of cervantes-tck/pom.xml (<excludedGroups>). Any future exclusion must be tracked in TCK.md with its justification.
Gaps resolved during the race to 100 %
The TCK surfaced several gaps between the spec and the initial implementation; every one of them was fixed in the engine, not masked by exclusions:
| Component | Resolved gap |
|---|---|
|
Lazy HTTP load + PEM-vs-JWKS auto-detection on the same URL + URL re-read after the server starts (the port is only known after bind). |
|
Added |
|
Parsing of JWK private key ( |
|
Explicit required-algorithm check + |
|
|
|
Unwrap |
|
Cookie-based token extraction (§9.2.3), error-case distinction, anonymous behaviour on missing token. |
|
Anonymous principal → |
Prerequisites delivered upstream
Two external fixes were necessary to reach 206/206 on the 2.1 TCK (still part of the 2.2 score):
-
cassini —
@Context SecurityContextpatch injected into a resource to reflect the JWT fromJwtAuthenticationFilter. Merged on Cassini main, REST TCK 4.0 (2535 tests) preserved. -
vauban — VAU-INJ-PRIM fix:
TypeMapperwas exposing a primitive injection point (boolean) asClassType[name=boolean]instead ofPrimitiveType, silently breaking@Claim booleaninjection. Fix + regression testPrimitiveQualifiedInjectionTest. Merged on Vauban main.