Cette page consolide la surface publique de Cervantes : artefacts à déclarer, modules JPMS exportés, annotations sécurité reconnues, toutes les clés mp.jwt.* lues par JwtAuthConfigProducer, et tous les algorithmes JOSE supportés par le moteur de signature et de chiffrement.

Artefacts Maven

groupId artifactId Rôle

io.vidocq.cervantes

cervantes-mp-jwt-api

Spec MP JWT 2.1 repackagée en module JPMS nommé (org.eclipse.microprofile.jwt). Aucune dépendance.

io.vidocq.cervantes

cervantes-api

SPI publique stable — JwtValidator, JwtConfig, KeyResolver, SignatureAlgorithm, JwtValidationException.

io.vidocq.cervantes

cervantes-core

Moteur de validation pur — parsing JWT, vérification signature (RS/ES/PS/HS), validation claims, chargement clés (PEM, JWKS), déchiffrement JWE. Aucun CDI, aucun JAX-RS.

io.vidocq.cervantes

cervantes-cdi-vauban

Producteur @RequestScoped JsonWebToken, BCE CervantesClaimExtension pour @Claim, JwtAuthConfigProducer qui produit le JwtValidator.

io.vidocq.cervantes

cervantes-jaxrs

JwtAuthenticationFilter (@PreMatching, AUTHENTICATION), RolesAllowedDynamicFeature + RolesAllowedRequestFilter, JwtSecurityContext.

io.vidocq.cervantes

cervantes-bench

Benchmarks JMH (vs SmallRye JWT, profil opt-in -Pcompare-smallrye). Pas pour la production.

io.vidocq.cervantes

cervantes-examples

Exemples (ProtectedResource avec @RolesAllowed + @Claim).

io.vidocq.cervantes

cervantes-tck

Runner officiel TCK MP JWT 2.1 — hors reactor (Model 4.0.0). Ne pas déclarer en dépendance applicative.

Toutes les versions à 0.1.0-SNAPSHOT au moment de la rédaction. Parent commun io.vidocq:vidocq-parent:1.0.0-SNAPSHOT.

Modules JPMS

Module Contenu

org.eclipse.microprofile.jwt

Repackaging de la spec — annotations @Claim, @LoginConfig, interfaces JsonWebToken, ClaimValue. Aucun requires.

io.vidocq.cervantes.api

io.vidocq.cervantes.api.* — SPI stable.

io.vidocq.cervantes.core

io.vidocq.cervantes.api. (réexport partiel), io.vidocq.cervantes.internal. (non exporté).

io.vidocq.cervantes.cdi.vauban

io.vidocq.cervantes.cdi.*JsonWebTokenContext, CervantesClaimExtension. provides BuildCompatibleExtension.

io.vidocq.cervantes.jaxrs

io.vidocq.cervantes.jaxrs.* — filtres, SecurityContext, DynamicFeature.

io.vidocq.cervantes.internal.* n’est jamais exporté. Toute classe applicative qui en dépend signale une régression à corriger.

Annotations sécurité reconnues

Annotation Effet Statut

@jakarta.annotation.security.RolesAllowed({"r1","r2"})

L’appelant doit posséder au moins un des rôles listés (un rôle est une chaîne du claim groups). Précédence : méthode > classe.

@jakarta.annotation.security.PermitAll

Endpoint ouvert à tous, anonyme inclus. Désactive les @RolesAllowed hérités.

@jakarta.annotation.security.DenyAll

Endpoint toujours rejeté en 403, quel que soit le token.

@org.eclipse.microprofile.jwt.Claim(value="…")

Qualifier d’injection CDI. La valeur typée est extraite du JsonWebToken courant. Voir tableau des types ci-dessous.

@org.eclipse.microprofile.jwt.Claim(standard=Claims.email)

Variante qui désigne le claim par son enum standard MP (au lieu d’une string libre).

@org.eclipse.microprofile.auth.LoginConfig(authMethod="MP-JWT")

Marqueur applicatif (compatibilité spec). Cervantes l’accepte sans action particulière — le filtre d’auth est de toute façon enregistré.

Types supportés pour @Claim

Type Java Sémantique

String

Coercion : JsonString.getString(), ou toString() pour autres scalaires.

Long, long

JsonNumber.longValue(). Champ primitif supporté depuis Vauban VAU-INJ-PRIM.

Integer, int

JsonNumber.intValueExact().

Double, double

JsonNumber.doubleValue().

Boolean, boolean

JsonValue.TRUE / JsonValue.FALSE.

Set<String>, List<String>

Pour les claims de type tableau (groups, aud). Préserve l’ordre dans List, sans doublon dans Set.

jakarta.json.JsonValue

Valeur brute parsée par Champollion.

JsonString, JsonNumber, JsonObject, JsonArray

Sous-types JSON-P.

Optional<T>

Eager. Résolu une fois à l’injection. Optional.empty() si claim absent.

org.eclipse.microprofile.jwt.ClaimValue<T>

Lazy MP. getValue() relit le token de la requête courante.

jakarta.inject.Provider<T>, jakarta.enterprise.inject.Instance<T>

Lazy CDI. get() relit le token courant.

java.util.function.Supplier<T>

Lazy JDK. get() relit le token courant.

String qualifié @Claim("raw_token")

Le token brut original — utile pour propager.

Clés MicroProfile Config mp.jwt.*

Toutes les clés sont lues via ConfigProvider.getConfig() — fourni par Ravel dans l’écosystème Vidocq.

Vérification de signature

Clé Effet

mp.jwt.verify.publickey

Clé publique inline. Accepte le PEM X.509 (-----BEGIN PUBLIC KEY-----) ou la base64 nue.

mp.jwt.verify.publickey.location

Emplacement de la clé publique : classpath:/…, file:/…, http://…, https://…. Auto-détection PEM vs JWKS (regex de format).

mp.jwt.verify.publickey.algorithm

Famille d’algorithme attendue (RS256, ES256, …). Défaut RS256. Refuse les tokens dont le header annonce une autre famille.

mp.jwt.verify.issuer

Émetteur attendu — string. Comparé strictement au claim iss du token.

mp.jwt.verify.audiences

Audiences acceptées — liste séparée par virgules. Au moins une intersection avec aud requise (sauf si vide).

mp.jwt.verify.clock.skew

Tolérance d’horloge en secondes (défaut 60). Applique à exp et nbf.

mp.jwt.verify.token.age

Âge maximal du token, en secondes depuis iat. Optionnel.

mp.jwt.verify.requireiat

Booléen — exiger la présence du claim iat. Défaut false.

Transport du token

Clé Effet

mp.jwt.token.header

Authorization (défaut, schéma Bearer) ou Cookie (extraction depuis un cookie nommé par mp.jwt.token.cookie).

mp.jwt.token.cookie

Nom du cookie portant le token quand mp.jwt.token.header=Cookie. Défaut Bearer.

Déchiffrement JWE (optionnel)

Clé Effet

mp.jwt.decrypt.key

Clé privée de déchiffrement inline. PEM PKCS#8.

mp.jwt.decrypt.key.location

Emplacement de la clé privée de déchiffrement.

mp.jwt.decrypt.key.algorithm

Algorithme d’enveloppement attendu : RSA-OAEP (défaut) ou RSA-OAEP-256. Si défini, refuse les JWE qui annoncent autre chose.

Algorithmes de signature supportés

Famille Algorithmes Implémentation JDK

RSA

RS256, RS384, RS512

Signature.getInstance("SHA256withRSA"/…). Clés ≥ 2048 bits recommandées.

RSA-PSS

PS256, PS384, PS512

Signature.getInstance("RSASSA-PSS") + PSSParameterSpec.

ECDSA

ES256, ES384, ES512

Signature.getInstance("SHA256withECDSA"/…). Courbes P-256/P-384/P-521. Transcodage R‖S ↔ DER interne (EcdsaSignatures).

HMAC

HS256, HS384, HS512

Mac.getInstance("HmacSHA256"/…). Hors profil par défaut MP, utilisable en interne.

Algorithmes JWE supportés

Étape Algorithme Notes

Enveloppement de clé (alg)

RSA-OAEP, RSA-OAEP-256

Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding") / …SHA-256….

Chiffrement de contenu (enc)

A256GCM

Cipher.getInstance("AES/GCM/NoPadding").

(planifié)

A128CBC-HS256

Non encore supporté — à ajouter si le TCK l’exige sur un futur jalon.

Comportement HTTP

Situation Code

Pas de token + endpoint @PermitAll

Endpoint exécuté en anonyme.

Pas de token + endpoint @RolesAllowed ou par défaut

401 Unauthorized.

Token présent, signature invalide / exp dépassé / iss non attendu / aud non attendu / alg non autorisé

401 Unauthorized.

Token valide mais sans rôle requis

403 Forbidden.

Token valide et rôle requis présent

200 OK (la méthode s’exécute).

Endpoint @DenyAll

403 Forbidden même avec token valide.

Compatibilité

  • Java 25 (LTS), Maven 3.9.16.

  • JAX-RS 4.0 (Cassini ou autre runtime conforme).

  • CDI 4.1 Lite (Vauban) avec support des BCE.

  • MicroProfile Config 3.1+ (Ravel).

  • JSON-P 2.1 (Champollion).

  • Pas de dépendance Jakarta EE Full Profile.

Bugs et benchmarks

  • BUG.md — bugs reproductibles tracés (vide à ce jour).

  • BENCH.md — JMH DefaultJwtValidator.validate vs SmallRye JWT (M7).

Pour aller plus loin