Reputation: 4995
I'm using the Auth0 java-jwt
library to generate JWT tokens, however, once generated I'm not able to verify the tokens.
This is the code I use to generate the token:
final JWTSigner signer = new JWTSigner(secret);
final HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("user", user);
claims.put("email", user.getEmail());
final String jwt = signer.sign(claims);
return jwt;
This is my secret and the token (it verifies correctly in https://jwt.io/):
secret:
sfnd984f94j3fjntoken: eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJ1c2VyIjp7ImlkIjoyLCJlbWFpbCI6InNhbnRob3NoQHh5ei5jb20iLCJwYXNzd29yZCI6IiQyYSQxMCRHSlNNRGtRRUEvRVNsRENJcVlud0R1Ly45YWRqRWRQalVvSWVKUmlsSmpSeHh6N2s2Q01xQyIsImZpcnN0X25hbWUiOiJzYW50aG9zaCIsImxhc3RfbmFtZSI6Imt1bWFyIiwic3RhdHVzIjoxLCJ0aXRsZSI6IkFzc29jIiwicm9sZXMiOlt7ImlkIjoxLCJyb2xlIjoiVVNFUiJ9XX0sImVtYWlsIjoic2FudGhvc2hAeHl6LmNvbSJ9.0SHNCgUWOijpYv7xcNoPiCwg_OFZQnsdi5l7YhCsSjU
When I use the same JWT token to verify it using the Auth0 method it fails (always ends up with a signature exception):
try {
final JWTVerifier verifier = new JWTVerifier(secret);
final Map<String, Object> claims= verifier.verify(jwt);
final String email = (String)claims.get("email");
user = userService.loadUserByEmail(email);
} catch (UsernameNotFoundException e) {
// Invalid Token
} catch (SignatureException e) {
System.out.println(e.toString());
} catch (IOException e) {
} catch (Exception e) {
}
I debugged the library and I think this is where the issue is (in JWTVerifier
class):
void verifySignature(String[] pieces, String algorithm)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Mac hmac = Mac.getInstance(algorithm);
hmac.init(new SecretKeySpec(decoder.decodeBase64(secret), algorithm));
byte[] sig = hmac.doFinal(
new StringBuilder(pieces[0]).append(".").append(pieces[1]).toString().getBytes());
if (!Arrays.equals(sig, decoder.decodeBase64(pieces[2]))) {
throw new SignatureException("signature verification failed");
}
}
This looks wrong to me because the pieces[1]
and pieces[0]
are decoded with the hmac.doFinal
where as the pieces[2]
is just plain base64 decoded.
Is my assumption right. Is this a bug in the library or am I getting something wrong?
Upvotes: 3
Views: 3694
Reputation: 57728
The version of JWTVerifier
being used assumes that the secret you pass is Base64url encoded so it automatically decodes it before using it as the key to validate the signature.
Given sfnd984f94j3fjn
is the actual secret and your version of JWTVerifier
automatically Base64url decodes whatever you pass it, you need to encode sfnd984f94j3fjn
in Base64url and pass the encoded version to JWTVerifier
.
Something similar to this:
import org.apache.commons.codec.binary.Base64;
// ...
Base64 encoder = new Base64(true);
encoder.encodeBase64("sfnd984f94j3fjn".getBytes());
You can see the automatic decoding of the secret happening on the following line of the version of JWTVerifier
class you're using:
hmac.init(new SecretKeySpec(decoder.decodeBase64(secret), algorithm));
An update on this, the latest version of the library does not seem to assume a Base64url encoding.
Upvotes: 1