JJWT Implementation module providing concrete implementations of JSON Web Token (JWT) creation, parsing, verification, and cryptographic operations for Java and Android applications.
—
The JWK (JSON Web Key) Support in JJWT Implementation provides comprehensive RFC 7517-compliant functionality for creating, parsing, managing, and using JSON Web Keys and JWK Sets. This includes support for all standard key types, operations, and X.509 certificate integration.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Jwk;
import io.jsonwebtoken.security.JwkSet;
import io.jsonwebtoken.security.JwkBuilder;
import io.jsonwebtoken.security.KeyOperation;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Set;
// Create JWK from existing key
SecretKey secretKey = Jwts.SIG.HS256.key().build();
Jwk<SecretKey> secretJwk = Jwts.JWK.builder(secretKey).build();
// Create JWK from key pair
KeyPair rsaKeyPair = Jwts.SIG.RS256.keyPair().build();
Jwk<PublicKey> publicJwk = Jwts.JWK.builder(rsaKeyPair.getPublic()).build();
Jwk<PrivateKey> privateJwk = Jwts.JWK.builder(rsaKeyPair.getPrivate()).build();
// Create JWK pair from KeyPair
Jwk<KeyPair> pairJwk = Jwts.JWK.builder(rsaKeyPair).build();// JWK with comprehensive metadata
Jwk<SecretKey> metadataJwk = Jwts.JWK.builder(secretKey)
.id("hmac-key-1")
.algorithm("HS256")
.operations()
.add(KeyOperation.SIGN)
.add(KeyOperation.VERIFY)
.and()
.build();
// RSA JWK with rich metadata
Jwk<PublicKey> rsaJwk = Jwts.JWK.builder(rsaKeyPair.getPublic())
.id("rsa-pub-2024-01")
.algorithm("RS256")
.keyUse("sig") // signature use
.operations()
.add(KeyOperation.VERIFY)
.and()
.build();
// EC JWK with curve information
KeyPair ecKeyPair = Jwts.SIG.ES256.keyPair().build();
Jwk<PublicKey> ecJwk = Jwts.JWK.builder(ecKeyPair.getPublic())
.id("ec-p256-key")
.algorithm("ES256")
.keyUse("sig")
.build();// HMAC secret keys
SecretKey hs256Key = Jwts.SIG.HS256.key().build();
SecretKey hs384Key = Jwts.SIG.HS384.key().build();
SecretKey hs512Key = Jwts.SIG.HS512.key().build();
Jwk<SecretKey> octJwk256 = Jwts.JWK.builder(hs256Key)
.id("hmac-256-key")
.algorithm("HS256")
.operations()
.add(KeyOperation.SIGN)
.add(KeyOperation.VERIFY)
.and()
.build();
// AES encryption keys
SecretKey aes128Key = Jwts.ENC.A128GCM.key().build();
SecretKey aes256Key = Jwts.ENC.A256GCM.key().build();
Jwk<SecretKey> aesJwk = Jwts.JWK.builder(aes256Key)
.id("aes-256-gcm-key")
.algorithm("A256GCM")
.operations()
.add(KeyOperation.ENCRYPT)
.add(KeyOperation.DECRYPT)
.and()
.build();
// Key wrapping keys
SecretKey kekKey = Jwts.KEY.A256KW.key().build();
Jwk<SecretKey> kekJwk = Jwts.JWK.builder(kekKey)
.id("kek-256")
.algorithm("A256KW")
.operations()
.add(KeyOperation.WRAP_KEY)
.add(KeyOperation.UNWRAP_KEY)
.and()
.build();// RSA signature keys
KeyPair rsaKeyPair = Jwts.SIG.RS256.keyPair()
.keySize(2048)
.build();
Jwk<PublicKey> rsaPublicJwk = Jwts.JWK.builder(rsaKeyPair.getPublic())
.id("rsa-2048-pub")
.algorithm("RS256")
.keyUse("sig")
.operations()
.add(KeyOperation.VERIFY)
.and()
.build();
Jwk<PrivateKey> rsaPrivateJwk = Jwts.JWK.builder(rsaKeyPair.getPrivate())
.id("rsa-2048-priv")
.algorithm("RS256")
.keyUse("sig")
.operations()
.add(KeyOperation.SIGN)
.and()
.build();
// RSA encryption keys
KeyPair rsaEncPair = Jwts.KEY.RSA_OAEP.keyPair()
.keySize(2048)
.build();
Jwk<PublicKey> rsaEncJwk = Jwts.JWK.builder(rsaEncPair.getPublic())
.id("rsa-enc-2048")
.algorithm("RSA-OAEP")
.keyUse("enc")
.operations()
.add(KeyOperation.ENCRYPT)
.and()
.build();
// RSA key pair JWK
Jwk<KeyPair> rsaPairJwk = Jwts.JWK.builder(rsaKeyPair)
.id("rsa-pair-2048")
.algorithm("RS256")
.keyUse("sig")
.build();// P-256 curve (ES256)
KeyPair ecP256Pair = Jwts.SIG.ES256.keyPair().build();
Jwk<PublicKey> ecP256Jwk = Jwts.JWK.builder(ecP256Pair.getPublic())
.id("ec-p256-pub")
.algorithm("ES256")
.keyUse("sig")
.operations()
.add(KeyOperation.VERIFY)
.and()
.build();
// P-384 curve (ES384)
KeyPair ecP384Pair = Jwts.SIG.ES384.keyPair().build();
Jwk<PublicKey> ecP384Jwk = Jwts.JWK.builder(ecP384Pair.getPublic())
.id("ec-p384-pub")
.algorithm("ES384")
.build();
// P-521 curve (ES512)
KeyPair ecP521Pair = Jwts.SIG.ES512.keyPair().build();
Jwk<KeyPair> ecP521PairJwk = Jwts.JWK.builder(ecP521Pair)
.id("ec-p521-pair")
.algorithm("ES512")
.build();
// ECDH keys for encryption
KeyPair ecdhPair = Jwts.KEY.ECDH_ES.keyPair().build();
Jwk<PublicKey> ecdhJwk = Jwts.JWK.builder(ecdhPair.getPublic())
.id("ecdh-p256")
.algorithm("ECDH-ES")
.keyUse("enc")
.operations()
.add(KeyOperation.DERIVE_KEY)
.and()
.build();// Ed25519 keys
KeyPair ed25519Pair = Jwts.SIG.EdDSA.keyPair().build();
Jwk<PublicKey> ed25519Jwk = Jwts.JWK.builder(ed25519Pair.getPublic())
.id("ed25519-key")
.algorithm("EdDSA")
.keyUse("sig")
.operations()
.add(KeyOperation.VERIFY)
.and()
.build();
Jwk<PrivateKey> ed25519PrivJwk = Jwts.JWK.builder(ed25519Pair.getPrivate())
.id("ed25519-priv")
.algorithm("EdDSA")
.keyUse("sig")
.operations()
.add(KeyOperation.SIGN)
.and()
.build();
// Ed448 support (if available)
try {
KeyPair ed448Pair = Jwts.SIG.EdDSA.keyPair()
.algorithm("Ed448")
.build();
Jwk<PublicKey> ed448Jwk = Jwts.JWK.builder(ed448Pair.getPublic())
.id("ed448-key")
.algorithm("EdDSA")
.build();
} catch (Exception e) {
// Ed448 might not be available in all JDK versions
}import io.jsonwebtoken.security.KeyOperationBuilder;
// Comprehensive key operations
Jwk<KeyPair> multiOpJwk = Jwts.JWK.builder(rsaKeyPair)
.id("multi-purpose-rsa")
.operations()
.add(KeyOperation.SIGN)
.add(KeyOperation.VERIFY)
.add(KeyOperation.ENCRYPT)
.add(KeyOperation.DECRYPT)
.add(KeyOperation.WRAP_KEY)
.add(KeyOperation.UNWRAP_KEY)
.and()
.build();
// Signature-only operations
Jwk<PublicKey> signOnlyJwk = Jwts.JWK.builder(publicKey)
.id("sign-only-key")
.keyUse("sig")
.operations()
.add(KeyOperation.VERIFY)
.and()
.build();
// Encryption-only operations
Jwk<PublicKey> encOnlyJwk = Jwts.JWK.builder(encryptionPublicKey)
.id("enc-only-key")
.keyUse("enc")
.operations()
.add(KeyOperation.ENCRYPT)
.add(KeyOperation.WRAP_KEY)
.and()
.build();import io.jsonwebtoken.impl.security.DefaultKeyOperationPolicyBuilder;
import io.jsonwebtoken.security.KeyOperationPolicy;
// Create operation policy
KeyOperationPolicy policy = Jwts.JWK.operationPolicy()
.add(KeyOperation.SIGN)
.add(KeyOperation.VERIFY)
.build();
// Apply policy during JWK creation
Jwk<KeyPair> policyJwk = Jwts.JWK.builder(keyPair)
.id("policy-controlled-key")
.operations()
.policy(policy)
.and()
.build();import java.security.cert.X509Certificate;
// Create JWK with X.509 certificate chain
X509Certificate[] certChain = loadCertificateChain();
PrivateKey certPrivateKey = loadPrivateKeyForCert();
Jwk<PrivateKey> certJwk = Jwts.JWK.builder(certPrivateKey)
.id("cert-key-2024")
.algorithm("RS256")
.x509CertChain(Arrays.asList(certChain))
.x509CertSha1Thumbprint(calculateSha1Thumbprint(certChain[0]))
.x509CertSha256Thumbprint(calculateSha256Thumbprint(certChain[0]))
.build();
// JWK with certificate URL
Jwk<PublicKey> certUrlJwk = Jwts.JWK.builder(publicKey)
.id("cert-url-key")
.x509Url(URI.create("https://certs.example.com/cert.pem"))
.build();import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
// Calculate certificate thumbprints
public static String calculateSha1Thumbprint(X509Certificate cert) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] der = cert.getEncoded();
byte[] digest = md.digest(der);
return Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
} catch (Exception e) {
throw new RuntimeException("Failed to calculate thumbprint", e);
}
}
public static String calculateSha256Thumbprint(X509Certificate cert) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] der = cert.getEncoded();
byte[] digest = md.digest(der);
return Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
} catch (Exception e) {
throw new RuntimeException("Failed to calculate thumbprint", e);
}
}
// Use thumbprints in JWK
Jwk<PublicKey> thumbprintJwk = Jwts.JWK.builder(certPublicKey)
.id("thumbprint-key")
.x509CertSha1Thumbprint(calculateSha1Thumbprint(certificate))
.x509CertSha256Thumbprint(calculateSha256Thumbprint(certificate))
.build();import io.jsonwebtoken.impl.security.DefaultJwkSetBuilder;
// Create JWK Set with multiple keys
Jwk<SecretKey> hmacJwk = Jwts.JWK.builder(hmacKey).id("hmac-1").build();
Jwk<PublicKey> rsaJwk = Jwts.JWK.builder(rsaPublicKey).id("rsa-1").build();
Jwk<PublicKey> ecJwk = Jwts.JWK.builder(ecPublicKey).id("ec-1").build();
JwkSet jwkSet = Jwts.JWK.set()
.add(hmacJwk)
.add(rsaJwk)
.add(ecJwk)
.build();
// Create JWK Set from collection
List<Jwk<?>> jwkList = Arrays.asList(hmacJwk, rsaJwk, ecJwk);
JwkSet collectionSet = Jwts.JWK.set()
.add(jwkList)
.build();
// Empty JWK Set
JwkSet emptySet = Jwts.JWK.set().build();// Access JWKs in set
Set<Jwk<?>> allJwks = jwkSet.getKeys();
int keyCount = jwkSet.size();
// Find JWK by ID
Jwk<?> foundJwk = jwkSet.getKeys().stream()
.filter(jwk -> "hmac-1".equals(jwk.getId()))
.findFirst()
.orElse(null);
// Filter by key type
List<Jwk<SecretKey>> secretKeys = jwkSet.getKeys().stream()
.filter(jwk -> jwk.toKey() instanceof SecretKey)
.map(jwk -> (Jwk<SecretKey>) jwk)
.collect(Collectors.toList());
// Filter by algorithm
List<Jwk<?>> rsaKeys = jwkSet.getKeys().stream()
.filter(jwk -> jwk.getAlgorithm() != null &&
jwk.getAlgorithm().startsWith("RS"))
.collect(Collectors.toList());// Serialize JWK to JSON
Jwk<SecretKey> secretJwk = Jwts.JWK.builder(secretKey)
.id("secret-key-1")
.algorithm("HS256")
.build();
String jwkJson = secretJwk.toJson();
// Pretty-printed JSON
String prettyJwkJson = secretJwk.toJson(true);
// JWK Set to JSON
String jwkSetJson = jwkSet.toJson();
String prettyJwkSetJson = jwkSet.toJson(true);import io.jsonwebtoken.impl.security.DefaultJwkParserBuilder;
// Parse JWK from JSON
String jwkJson = """
{
"kty": "RSA",
"kid": "rsa-key-1",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
""";
Jwk<?> parsedJwk = Jwts.JWK.parser().build().parse(jwkJson);
// Type-safe parsing
if (parsedJwk.toKey() instanceof PublicKey) {
Jwk<PublicKey> publicJwk = (Jwk<PublicKey>) parsedJwk;
PublicKey publicKey = publicJwk.toKey();
}
// Parse JWK Set from JSON
String jwkSetJson = """
{
"keys": [
{
"kty": "RSA",
"kid": "rsa-1",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
},
{
"kty": "EC",
"kid": "ec-1",
"use": "sig",
"alg": "ES256",
"crv": "P-256",
"x": "...",
"y": "..."
}
]
}
""";
JwkSet parsedSet = Jwts.JWK.setParser().build().parse(jwkSetJson);import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.JwkParser;
// Configure JWK parser with custom deserializer
Deserializer<Map<String, ?>> customDeserializer = createCustomDeserializer();
JwkParser customParser = Jwts.JWK.parser()
.json(customDeserializer)
.build();
// Provider-specific parsing
Provider customProvider = new BouncyCastleProvider();
JwkParser providerParser = Jwts.JWK.parser()
.provider(customProvider)
.build();
// Operation policy enforcement
KeyOperationPolicy restrictivePolicy = Jwts.JWK.operationPolicy()
.add(KeyOperation.VERIFY)
.build();
JwkParser restrictedParser = Jwts.JWK.parser()
.operationPolicy(restrictivePolicy)
.build();import io.jsonwebtoken.impl.security.DefaultJwkSetParserBuilder;
// Configure JWK Set parser
JwkSetParser setParser = Jwts.JWK.setParser()
.provider(customProvider)
.operationPolicy(policy)
.build();
// Parse with validation
JwkSet validatedSet = setParser.parse(jwkSetJson);
// Verify all keys meet policy requirements
boolean allKeysValid = validatedSet.getKeys().stream()
.allMatch(jwk -> validateKeyOperations(jwk));import io.jsonwebtoken.impl.security.DefaultDynamicJwkBuilder;
// Dynamic JWK building based on key type
Key unknownKey = getKeyFromSomewhere();
Jwk<?> dynamicJwk = Jwts.JWK.builder(unknownKey)
.id("dynamic-key")
.build();
// Type detection and handling
if (dynamicJwk.toKey() instanceof SecretKey) {
SecretKey secretKey = (SecretKey) dynamicJwk.toKey();
// Handle symmetric key
} else if (dynamicJwk.toKey() instanceof PublicKey) {
PublicKey publicKey = (PublicKey) dynamicJwk.toKey();
// Handle asymmetric public key
} else if (dynamicJwk.toKey() instanceof PrivateKey) {
PrivateKey privateKey = (PrivateKey) dynamicJwk.toKey();
// Handle asymmetric private key
}// Create JWT using JWK
Jwk<PrivateKey> signingJwk = Jwts.JWK.builder(privateKey)
.id("signing-key-1")
.algorithm("RS256")
.build();
String jwt = Jwts.builder()
.subject("user")
.header()
.keyId(signingJwk.getId())
.and()
.signWith(signingJwk.toKey())
.compact();
// Create JWE using JWK
Jwk<PublicKey> encryptionJwk = Jwts.JWK.builder(encryptionPublicKey)
.id("encryption-key-1")
.algorithm("RSA-OAEP")
.build();
String jwe = Jwts.builder()
.subject("user")
.header()
.keyId(encryptionJwk.getId())
.and()
.encryptWith(encryptionJwk.toKey(), Jwts.KEY.RSA_OAEP, Jwts.ENC.A256GCM)
.compact();// Key locator using JWK Set
JwkSet keySet = loadJwkSet();
Locator<Key> jwkLocator = header -> {
String keyId = header.getKeyId();
return keySet.getKeys().stream()
.filter(jwk -> keyId.equals(jwk.getId()))
.map(Jwk::toKey)
.findFirst()
.orElseThrow(() -> new SecurityException("Key not found: " + keyId));
};
JwtParser jwkParser = Jwts.parser()
.keyLocator(jwkLocator)
.build();// JWK with custom parameters
Jwk<SecretKey> customParamJwk = Jwts.JWK.builder(secretKey)
.id("custom-key")
.algorithm("HS256")
.add("custom-param", "custom-value")
.add("version", "1.0")
.add("environment", "production")
.build();
// Access custom parameters
String customValue = customParamJwk.get("custom-param");
String version = customParamJwk.get("version");// Validate JWK structure and content
public static boolean validateJwk(Jwk<?> jwk) {
// Check required fields
if (jwk.getId() == null || jwk.getId().isEmpty()) {
return false;
}
// Validate key operations
Set<KeyOperation> operations = jwk.getOperations();
if (operations != null && !operations.isEmpty()) {
// Ensure operations are compatible with key type
Key key = jwk.toKey();
if (key instanceof SecretKey) {
// Validate symmetric key operations
return operations.stream().allMatch(op ->
op == KeyOperation.SIGN ||
op == KeyOperation.VERIFY ||
op == KeyOperation.ENCRYPT ||
op == KeyOperation.DECRYPT ||
op == KeyOperation.WRAP_KEY ||
op == KeyOperation.UNWRAP_KEY
);
}
}
return true;
}
// Validate JWK Set
public static boolean validateJwkSet(JwkSet jwkSet) {
return jwkSet.getKeys().stream()
.allMatch(jwk -> validateJwk(jwk));
}The JWK Support implementation provides comprehensive, RFC 7517-compliant JSON Web Key functionality with full support for all standard key types, operations, X.509 integration, and seamless JWT/JWS/JWE integration.
Install with Tessl CLI
npx tessl i tessl/maven-io-jsonwebtoken--jjwt-impl