Skip to content
Connect2id

FAQ

I appended an extra char to the BASE64URL signature and the JWS validation still passes, this must be a bug!

According to the JWS RFC 7515, the signature validation is performed at byte level, not by comparing the BASE64URL encodings.

Appending an extra character to a BASE64URL string will not necessarily modify the underlying bytes as returned by the BASE64 decoder.

Example JWS RSA signature:

pWOUF4Gkgqy9Il7KYfIWpS99m1K17-LdMDukwD6LqKol3RUZYc3XF0HzJ6F97iXFcK76FHgESDlpm3-
44AlA1zfUDclx6aHKXfJPA-0yB5fPGocJf7kURMh6tCdTkdbi

Decoded to bytes, in hex:

a5 63 94 17 81 a4 82 ac bd 22 5e ca 61 f2 16 a5 2f 7d 9b 52 b5 ef e2 dd 30 3b
a4 c0 3e 8b a8 aa 25 dd 15 19 61 cd d7 17 41 f3 27 a1 7d ee 25 c5 70 ae fa 14
78 04 48 39 69 9b 7f b8 e0 09 40 d7 37 d4 0d c9 71 e9 a1 ca 5d f2 4f 03 ed 32
07 97 cf 1a 87 09 7f b9 14 44 c8 7a b4 27 53 91 d6 e2

Let’s add the a character at the end of the JWS signature:

pWOUF4Gkgqy9Il7KYfIWpS99m1K17-LdMDukwD6LqKol3RUZYc3XF0HzJ6F97iXFcK76FHgESDlpm3-
44AlA1zfUDclx6aHKXfJPA-0yB5fPGocJf7kURMh6tCdTkdbia

The BASE64 decoder returns the same bytes as before:

a5 63 94 17 81 a4 82 ac bd 22 5e ca 61 f2 16 a5 2f 7d 9b 52 b5 ef e2 dd 30 3b
a4 c0 3e 8b a8 aa 25 dd 15 19 61 cd d7 17 41 f3 27 a1 7d ee 25 c5 70 ae fa 14
78 04 48 39 69 9b 7f b8 e0 09 40 d7 37 d4 0d c9 71 e9 a1 ca 5d f2 4f 03 ed 32
07 97 cf 1a 87 09 7f b9 14 44 c8 7a b4 27 53 91 d6 e2

That’s because the extra char at the end results in a incomplete byte (six bits instead of eight) that gets discarded by the library BASE64 decoder. A survey of the commonly available BASE64 implementations in Java showed two approaches when reaching an incomplete byte at the end - discarding it or throwing an exception. Both approaches guarantee the return of complete bytes from the BASE64 decoding. The Nimbus JOSE+JWT library uses a constant time codec that ignores unrecognised chars (like new lines for formatting purposes) and discards any incomplete trailing byte.

Illegal key size exception

Are you getting an java.security.InvalidKeyException with an Illegal key size message?

The standard Java edition is subject to a cryptographic export restriction that limits AES key sizes to 128 bits (and other keys to a similar strength). Attempting to use longer keys will result in the above exception.

To enable longer keys you need to add a couple of policy files provided by Oracle to your Java installation.

Unsupported algorithm / cipher / etc exception

The Nimbus JOSE+JWT library uses Java’s pluggable architecture (JCA) to perform most underlying crypto operations for JWS and JWE.

A java.security.NoSuchAlgorithmException indicates that your Java runtime is missing support for the JWS or JWE algorithms that you want to use.

com.nimbusds.jose.JOSEException: Couldn't create AES/GCM/NoPadding cipher: Cannot find any provider supporting AES/GCM/NoPadding

	at com.nimbusds.jose.crypto.AESGCM.encrypt(AESGCM.java:93)
	at com.nimbusds.jose.crypto.ContentCryptoProvider.encrypt(ContentCryptoProvider.java:169)
	at com.nimbusds.jose.crypto.DirectEncrypter.encrypt(DirectEncrypter.java:118)
	at com.nimbusds.jose.JWEObject.encrypt(JWEObject.java:353)
    ...
Caused by: java.security.NoSuchAlgorithmException: Cannot find any provider supporting AES/GCM/NoPadding
	at javax.crypto.Cipher.getInstance(Cipher.java:529)
	at com.nimbusds.jose.crypto.AESGCM.encrypt(AESGCM.java:85)
	... 34 more

In that case follow the instructions to add a JCA provider for the missing algorithms.

RemoteJWKSet times out

Increase the timeouts (in milliseconds) from their default values, zero implies no timeout.

System.out.println("Default connect timeout: " + RemoteJWKSet.DEFAULT_HTTP_CONNECT_TIMEOUT + "ms");
System.out.println("Default read timeout: " + RemoteJWKSet.DEFAULT_HTTP_READ_TIMEOUT + "ms");

int connectTimeoutMs = 1500;
int readTimeoutMs = 1500;
new RemoteJWKSet(url, new DefaultResourceRetriever(connectTimeoutMs, readTimeoutMs));

How to include the key ID (kid) in the JOSE header?

The key ID is an arbitrary string used to identify the key used in a JWS or JWE. An OpenID Connect server for instance uses an RSA public / private key pair to secure the issued identity tokens. The private RSA key is used to sign the JWS, while the public key (made available to clients for download) is used to verify the JWS signature.

It’s a good security practise to expire keys after a certain time, so a new RSA key pair is periodically generated and added under a new unique ID to the JWK set while retaining the previous keys.

Receiving a JWS object with a key ID for which the client has no previously cached public RSA key acts as a signal for the client to go and fetch the new key from the OpenID Connect server.

How to add a key ID to the JWS message:

String keyID = "001";

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256)
    .keyID(keyID)
    .build();

JWSObject jws = new JWSObject(header, new Payload("Hello world!"));

If you have a JWK:

RSAKey rsaJWK = RSAKey.parse(string);

JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.RS256)
    .keyID(rsaJWK.getKeyID())
    .build();

JWSObject jws = new JWSObject(header, new Payload("Hello world!"));

Note that only JWS and JWE objects support the key ID header parameter. Unsecured (plain) objects and JWTs don’t allow it.

To retrieve the key ID from a JWS or JWE object:

JWSObject jws = JWSObject.parse(string);
String keyID = jws.getHeader().getKeyID();

Is the Samsung Knox key store supported?

Yes, the TIMA key store is supported because it’s PKCS#11 compliant. Just use the TIMAKeyStore keyword when instantiating a KeyStore object for it:

// Load and init the key store
KeyStore timaKeyStore = KeyStore.getInstance("TIMAKeyStore");
timaKeyStore.load(null, null);

You can then use the KeyStore methods to retrieve the desired key for signing or encryption. You can also obtain a JWK set representation of all keys found in store:

JWKSet jwkSet = JWKSet.load(timaKeyStore, null);

How to limit the accepted JWS / JWE algorithms?

Note: This feature was removed in version 4.0. Use the new JOSE / JWT processing framework instead.

The JWSVerifier and JWEDecrypter interfaces provide a handy setAcceptedAlgorithms method for that.

Say a JWS verifier supports algorithms X, Y and Z. You however want the verifier to allow only JWS messages with algorithms X and Y only, and reject those with Z. That’s what the accepted algorithms setter does:

Set<JWSAlgorithm> acceptedAlgs = new HashSet<>();
acceptedAlgs.add(JWSAlgorithm.X);
acceptedAlgs.add(JWSAlgorithm.Y);

jwsVerifier.setAcceptedAlgorithms(acceptedAlgs);

How to check if a JWT string is signed or encrypted?

Use the generic com.nimbusds.jwt.JWTParser:

JWT jwt;

try {
	jwt = JWTParser.parse(jwtString);
} catch (ParseException e) {
	// Invalid JWT...
}

if (jwt instanceof SignedJWT) {
	// We have a JWS protected JWT
} else if (jwt instanceof EncryptedJWT) {
 	// We have a JWT protected JWT
} else {
	// We have an unsecured (plain) JWT
}

What is the difference between JCA and JCE?

The JCA acronym stands for Java Cryptography Architecture. It defines a pluggable framework for cryptography in Java in the java.security package and its descendants. The JCA APIs cover encryption, key generation and management, secure random number generation and certificates.

The JCE acronym stands for Java Cryptography Extension. It provides an official framework and JCA implementation, which classes are found in the javax.crypto package.

For more info check out Suresh Yadagiri’s article.

Will an upgrade / change to my BouncyCastle version break things?

No, it shouldn’t. The Nimbus JOSE+JWT library doesn’t call any BouncyCastle APIs directly. All crypto calls are instead routed via the standard Java crypto APIs, which then determines the appropriate implementation (builtin, BouncyCastle or other).

For more info: See plugging JCA algorithms.

I’m getting a block size exception on RSA encryption

If you’re getting an IllegalBlockSizeException this is an indication that the RSA encryption key is too short for the chosen JWE alg + enc combination, e.g. RSA-OAEP-256 with A256CBC-HS512 content encryption:

javax.crypto.IllegalBlockSizeException: Data must not be longer
than 62 bytes
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:344)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.nimbusds.jose.crypto.RSA_OAEP_256.encryptCEK(RSA_OAEP_256.java:73)
... 38 more

The solution is to switch to a longer RSA key. An RSA key size of 2048 bits will be sufficiently long for any of the standard JOSE algorithms with RSA based encryption.

To make debugging easier for developers version 4.31.1 of the library updated the JOSEException code to return a more informative message:

RSA block size exception: The RSA key is too short, try a longer one