Is Keys.password
supported to sign JWT tokens?
#993
-
Hi I am currently using version Here is the snippet of code I used: package example;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.Password;
public class Example {
public static void main(String[] args) {
String secretString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
Password key = Keys.password(secretString.toCharArray());
String jwt = Jwts.builder().claim("foo", "bar").signWith(key).compact();
System.out.println(jwt);
}
} I just assumed looking at SecretKey Formats section that I was able to sign a JWT token using that method, Am I using the API incorrectly or missing something? Thanks in advance for your help |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Hi @pgmarc ! Plaintext passwords (and their The only JWA-defined password input algorithms are for Key Encryption using PBES2, used during JWT encryption, not signing. So, because As for using a plaintext string to get a HMAC key, the intended API is to use The input to that method is expected to be the encoded bytes of a previously created valid HMAC key, for example: SecretKey key = Jwts.SIG.HS512.key().build();
String secretString = Encoders.BASE64.encode(key.getEncoded());
// WARNING: `secretString` is not encrypted, it must be saved somewhere safe, ideally encrypted first. Then, during application startup, the String secretString = getFromApplicationConfigAndDecrypt();
byte[] decoded = Decoders.BASE64.decode(secretString);
SecretKey key = null;
try {
key = Keys.hmacKeyFor(decoded);
} finally {
java.util.Arrays.fill(decoded, (byte) 0);
} Then later during runtime when needing to sign JWTs: String jwt = Jwts.builder().claim("foo", "bar").signWith(key).compact();
// etc ... One could abuse this API to get around having validly-encoded key bytes: // HERE BE DRAGONS. THOU ART FOREWARNED.
// This is cryptographically unsafe and will fail any reasonable security audit:
SecretKey key = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8)); // INSECURE, DO NOT DO THIS That might be your workaround, but I strongly advise contacting whoever is forcing this as a requirement in the project and advocate the cryptographically safe way. The application's security model is at risk otherwise. I hope that helps! |
Beta Was this translation helpful? Give feedback.
Hi @pgmarc !
Plaintext passwords (and their
Password
type complement) are unsafe inputs for any cryptographic algorithms other than key derivation algorithms. Key derivation algorithms work by taking an unsafe input (like a poor-entropy text password) and they produce/output a cryptographically safe key that is sufficiently strong to use in the actual desired algorithm (e.g. signature algorithm, encryption algorithm, etc).The only JWA-defined password input algorithms are for Key Encryption using PBES2, used during JWT encryption, not signing.
So, because
.signWith
attempts to find the most suitable mac or signature algorithm for the specified key, and asPassword
instances are not suita…