Here is a similar question I posted and got help on that might help. I think you want to use the x5c, which is the full certificate chain, and take the public key from that to validate the signature of your JWT. The modulus and exponent (n and e) will produce the public key of only the first certificate in the certificate chain, but that is insufficient to validate the signature.
Here are some code snippets I used to extract the public key from the endpoint. The AzurePublicKey class is just the POJO for the json.
private PublicKey convertKey(AzurePublicKey azKey) {
PublicKey publicKey = null;
BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getN()));
BigInteger exponent = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getE()));
try {
publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
// load cert
CertificateFactory factory;
X509Certificate cert = null;
try {
factory = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(azKey.getX5c().iterator().next())));
} catch (CertificateException e) {
e.printStackTrace();
}
// grab public key
publicKey = (RSAPublicKey)cert.getPublicKey();
System.out.println("[");
System.out.println("kid : " + azKey.getKeyIdentifier());
System.out.println("e : " + azKey.getE());
System.out.println("n : " + azKey.getN());
System.out.println("Maybe this : " + DatatypeConverter.printBase64Binary(publicKey.getEncoded()) );
System.out.println("]");
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return publicKey;
}
And the code to use that public key to validate the signature using the JJWT library.
Jws<Claims> claims = Jwts.parser()
.setSigningKeyResolver(signingKeyResolver)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""));
String issuer = claims.getBody().getIssuer();
if(issuer == null || !VALID_ISSUERS.contains(issuer))
throw new IncorrectClaimException(claims.getHeader(), claims.getBody(), "Invalid Issuer in Token.", new Throwable("Invalid Issuer in Token."));
The SigningKeyResolverImpl just provides the correct public key based on the kid
of the token header. If parsing does not throw an exception you can validate the token claims against values you were expecting as I've validated the issuer here against a list of VALID_ISSUERS
that I'm expecting.
It's been a while so I'm fuzzy but I hope this helps.