The official MicroProfile JWT 2.1 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 206 / 206 on the 2.1 release (May 2026, milestone M6).
Status
| Metric | Value |
|---|---|
Tests executed |
206 |
Passed |
206 ✅ |
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.1 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.1.sh script at the repository root drives every variant.
# Smoke — single fast test to validate the installation
./run-official-tck-mp-jwt-2.1.sh
# Full suite — equivalent to the official 206-test TCK
./run-official-tck-mp-jwt-2.1.sh all
# Targeted test via -Dtest=
./run-official-tck-mp-jwt-2.1.sh -Dtest=PublicKeyAsPEMTest
The runner uses Arquillian. The Surefire report lands in cervantes-tck/target/surefire-reports/.
Runner architecture
cervantes-tck is deliberately outside the reactor: its pom.xml uses standalone modelVersion 4.0.0 with no <parent>. Template mirrored from heisenberg-tck.
|
This detachment is forced by ShrinkWrap Maven Resolver 3.3, transitively pulled in by the official TCK, which cannot parse Model 4.1.0 POMs and crashes on the Vidocq reactor. The rule is documented at the workspace root: do not reintegrate |
Stack assembled by the runner:
| Layer | Component |
|---|---|
Spec |
|
MP JWT implementation |
|
CDI container |
Vauban ( |
Arquillian container |
|
HTTP transport |
Chappe ( |
Test framework |
Arquillian + REST (the MP JWT TCK is not TestNG-only, unlike the MP FT TCK) |
Documented exclusions
Two exclusions, not applicable to the Core + JWT profile targeted by Cervantes:
| Exclusion | Justification |
|---|---|
Tests under |
Tests targeting the Jakarta EE Full container servlet profile. Cervantes targets the Core (MicroProfile) profile — no Servlet 6.1 commitment. The Servlet role is filled by Foy, out of scope for this MP JWT implementation. |
TestNG group |
Tests marked optional by the spec for Jakarta EE Security 3.0 integration. Not required for MP JWT 2.1 conformance. |
The exclusions are listed in the Arquillian/TestNG suite file under cervantes-tck/src/test/resources/. 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:
-
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.