jwtk/jjwt · error · InvalidKeyException
Unable to encode SecretKey to JWK
Error message
Unable to encode SecretKey to JWK: ${t.getMessage()} What it means
Thrown as InvalidKeyException when a SecretKey cannot be encoded to bytes (KeysBridge.getEncoded) and Base64URL-encoded into the JWK 'k' parameter while building a SecretJwk. The original throwable's message is included as the cause.
Solutions
- Use an exportable SecretKey (e.g. generated with Keys.secretKeyFor or SecretKeySpec) when building a JWK.
- If the key lives in an HSM/keystore, do not build a JWK from it; reference it by key ID instead of embedding key material.
- Check the cause for the exact provider failure and ensure the key is not destroyed or cleared before JWK creation.
Example fix
// before SecretKey key = keystore.getKey(alias, null); // non-exportable HSM key Jwk jwk = Jwts.builder().keys().build(key); // after SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // exportable Jwk jwk = Jwts.builder().keys().build(key);
Defensive patterns
Strategy: validation
Validate before calling
byte[] encoded = secretKey.getEncoded();
if (encoded == null || encoded.length == 0) throw new IllegalStateException("SecretKey is not exportable"); Type guard
boolean isExportableSecretKey(SecretKey k) { return k.getEncoded() != null && k.getEncoded().length > 0; } Try / catch
try { /* build SecretJwk */ } catch (InvalidKeyException e) { throw new IllegalStateException("Key not exportable; use an in-memory SecretKey", e); } Prevention
- Only build JWKs from in-memory, exportable SecretKeys (SecretKeySpec / Keys.secretKeyFor).
- Never attempt to embed HSM/Android-Keystore keys into JWKs.
- Ensure keys are not destroyed/cleared before JWK creation.
When it happens
Trigger: Building a JWK from a SecretKey whose getEncoded() returns null or fails, e.g. hardware/PKCS11-backed or destroyable keys, or keys from providers that refuse export when calling JwkBuilder/JWK creation APIs.
Common situations: Using keys stored in an HSM/keystore that prohibit key export; keys already destroyed (DestroyFailedException paths); platform-specific providers (Android Keystore) returning null encodings.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid Secret JWK value ' '. Secret JWKs may only be used…
- JWE Header epk value is not an Elliptic Curve Public JWK…
- Secret JWK value is ' ', but the length is smaller than the…
- Unable to create from JWK
- Unable to derive RSAPublicKey from RSAPrivateKey
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/513acdf464243212.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/SecretJwkFactory.java:58
*/
class SecretJwkFactory extends AbstractFamilyJwkFactory<SecretKey, SecretJwk> {
SecretJwkFactory() {
super(DefaultSecretJwk.TYPE_VALUE, SecretKey.class, DefaultSecretJwk.PARAMS);
}
@Override
protected SecretJwk createJwkFromKey(JwkContext<SecretKey> ctx) {
SecretKey key = Assert.notNull(ctx.getKey(), "JwkContext key cannot be null.");
String k;
byte[] encoded = null;
try {
encoded = KeysBridge.getEncoded(key);
k = Encoders.BASE64URL.encode(encoded);
Assert.hasText(k, "k value cannot be null or empty.");
} catch (Throwable t) {
String msg = "Unable to encode SecretKey to JWK: " + t.getMessage();
throw new InvalidKeyException(msg, t);
} finally {
Bytes.clear(encoded);
}
MacAlgorithm mac = DefaultMacAlgorithm.findByKey(key);
if (mac != null) {
ctx.put(AbstractJwk.ALG.getId(), mac.getId());
}
ctx.put(DefaultSecretJwk.K.getId(), k);
return createJwkFromValues(ctx);
}
private static void assertKeyBitLength(byte[] bytes, MacAlgorithm alg) {
long bitLen = Bytes.bitLength(bytes);
long requiredBitLen = alg.getKeyBitLength();
if (bitLen < requiredBitLen) {View on GitHub (pinned to fb71496164)