extensions/smallrye-jwt-build/deployment/src/main/resources/META-INF/quarkus-skill.md
Use the fluent Jwt builder from io.smallrye.jwt.build.Jwt:
String token = Jwt.upn("alice")
.groups(Set.of("User", "Admin"))
.issuer("https://example.com")
.expiresIn(Duration.ofHours(1))
.sign();
Common claim methods:
Jwt.upn("username") — sets the upn (User Principal Name) claimJwt.subject("sub") — sets the sub claimJwt.preferredUserName("name") — sets preferred_usernameJwt.groups(Set.of(...)) — sets groups claim (used for @RolesAllowed)Jwt.claim("key", value) — sets any custom claimJwt.issuer("url") — sets the iss claim (overrides config)Jwt.expiresIn(Duration) or Jwt.expiresAt(Instant) — controls expirationIn dev/test mode, Quarkus auto-generates an RSA key pair — no key configuration needed. The generated keys are set as:
mp.jwt.verify.publickey — for verificationsmallrye.jwt.sign.key — for signingKeys regenerate on each app restart.
For production, provide your own keys:
# Signing key (private)
smallrye.jwt.sign.key.location=privateKey.pem
# Verification key (public) — if also verifying tokens in this app
mp.jwt.verify.publickey.location=publicKey.pem
Place key files in src/main/resources/.
# Issuer — must match mp.jwt.verify.issuer if verifying in the same app
smallrye.jwt.new-token.issuer=https://example.com
mp.jwt.verify.issuer=https://example.com
# Token lifespan in seconds (default: 300 = 5 minutes)
smallrye.jwt.new-token.lifespan=3600
Inject JWTParser (from smallrye-jwt) to parse and verify tokens:
@Inject JWTParser jwtParser;
@Test
void verifyToken() throws Exception {
String token = Jwt.upn("alice").groups(Set.of("User")).sign();
JsonWebToken jwt = jwtParser.parse(token);
assertEquals("alice", jwt.getName());
assertTrue(jwt.getGroups().contains("User"));
}
Encrypt a JWT instead of (or in addition to) signing:
// Encrypt only
String jwe = Jwt.upn("alice").jwe().encrypt();
// Sign then encrypt (inner-sign)
String signedAndEncrypted = Jwt.upn("alice").innerSign().encrypt();
smallrye.jwt.new-token.issuer and mp.jwt.verify.issuer must match if you both generate and verify tokens in the same app. Mismatches cause silent verification failures.smallrye.jwt.new-token.lifespan for longer-lived tokens.sign() uses the configured private key — in dev mode this is auto-generated. In production you must provide smallrye.jwt.sign.key.location.Jwt is a static entry point, not an injectable bean — use Jwt.claims() or Jwt.upn() directly, no @Inject needed.