CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-jsonwebtoken--jjwt-impl

JJWT Implementation module providing concrete implementations of JSON Web Token (JWT) creation, parsing, verification, and cryptographic operations for Java and Android applications.

Pending
Overview
Eval results
Files

jwk-support.mddocs/

JWK Support

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.

Core JWK Classes

JWK Building and Creation

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 Metadata

// 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();

Key Type Support

Symmetric Keys (oct)

// 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 Keys

// 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();

Elliptic Curve Keys

// 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();

OKP Keys (EdDSA)

// 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
}

JWK Operations and Key Use

Key Operations

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();

Key Operation Policies

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();

X.509 Certificate Integration

JWK with Certificate Chain

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();

Certificate Thumbprints

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();

JWK Sets

Creating JWK Sets

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();

JWK Set Operations

// 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());

JSON Serialization

JWK to JSON

// 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);

JSON to JWK Parsing

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);

JWK Parser Configuration

Custom JWK Parser

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();

JWK Set Parser Configuration

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));

Dynamic JWK Building

Dynamic Key Type Detection

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
}

JWK Integration with JWT Operations

Using JWK for JWT Creation

// 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();

JWK-based Key Resolution

// 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();

Advanced JWK Features

Custom JWK Parameters

// 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");

JWK Validation

// 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

docs

compression.md

index.md

jwk-support.md

jwt-building.md

jwt-parsing.md

security-algorithms.md

utilities.md

tile.json