Lets see how we can process and validate the JWT token using simple java code. We have generated a sample JWT token from WSO2IS.. You can find it in following
eyJ0eXAiOiJKV1QiLCJhbGciOiJTSEEyNTZ3aXRoUlNBIiwieDV0IjoiTm1KbU9HVXhNelpsWWpNMlpEUmhOVFpsWVRBMVl6ZGhaVFJpT1dFME5XSTJNMkptT1RjMVpBIn0.eyJpc3MiOiJodHRwOi8vd3NvMi5vcmcvZ2F0ZXdheSIsImV4cCI6MTQyNjczODI1MDkzNSwiaHR0cDovL3dzbzIub3JnL2dhdGV3YXkvc3Vic2NyaWJlciI6ImFkbWluIiwiaHR0cDovL3dzbzIub3JnL2dhdGV3YXkvYXBwbGljYXRpb25uYW1lIjoiT3BlbmlkQ29ubmVjdCIsImh0dHA6Ly93c28yLm9yZy9nYXRld2F5L2VuZHVzZXIiOiJhc2VsYUBjYXJib24uc3VwZXIiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy9jb3VudHJ5IjoiVW5pdGVkIFN0YXRlcyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2VtYWlsYWRkcmVzcyI6ImFzZWxhQHNvYXNlY3VyaXR5Lm9yZyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2Z1bGxuYW1lIjoiYXNlbGEiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy9naXZlbm5hbWUiOiJBc2VsYSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2xhc3RuYW1lIjoiUGF0aGJlcml5YSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL29yZ2FuaXphdGlvbiI6InNvYXNlY3VyaXR5Lm9yZyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL3JvbGUiOiJJbnRlcm5hbC9ldmVyeW9uZSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL3Nob3ciOiJVbml0ZWQgU3RhdGVzIiwgImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvc3R1ZGlvIjoiQXNlbGEiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy90ZWxlcGhvbmUiOiIrOTQ3Nzc2MjU5MzMifQ.d57VGVAhZmTpIMl8hiIUO8D7hAZl-bZm5TnDW9si3qnHFliMHsxlE6HJ7bSjmoobIgdqJ7xToWtOm2orrQKFxzF4xxkpNeU1-qGFoG6-IyRF-JAJao0xq6WIGk8fR2BSN_zxsNbR84-3FMWd6mljPnImWYLe_8mOBFyDcsuDCkk
It has been signed using RS256 (RSA algorithm using SHA-256). WSO2IS uses its primary keystore to sign the JWT token. By default primary keystore is “wso2carbon.jks” file. Therefore this JWT token has been signed using private key of “wso2carbon.jks” file. So, To validate the signature of JWT, we need the public certificate of “wso2carbon.jks” file.
Please note, we are using Apache common codec library for Base64 Url decoding and simple json library for building the JSON object. You can find them from here.
You just need to add above libraries in to following code and run it. Please note, you need to configure a trust store which contains the public certificate of wso2carbon.jks” file. You can find it from here. You can use this for validation and processing purpose of JWT token (specially retrieved from WSO2IS ).. Java class can be found from here as well.
import org.apache.commons.codec.binary.Base64; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import java.io.FileInputStream; import java.security.KeyStore; import java.security.MessageDigest; import java.security.Signature; import java.security.cert.Certificate; import java.util.Enumeration; /** * Simple JWT processor. This is specially written for JWT generated by WSO2IS */ public class SimpleJWTProcessor { private static final Base64 base64Url = new Base64(true); private static final String trustStore = "/trust-store/client-truststore.jks" ; private static final String trustStorePassword = "wso2carbon"; private JSONObject jsonHeaderObject; private JSONObject jsonClaimObject; private String jwtToken; public SimpleJWTProcessor(String jwtToken) { this.jwtToken = jwtToken; } protected boolean isValid(){ String[] jwtTokenValues = jwtToken.split("\."); String jwtAssertion = null; byte[] jwtSignature = null; if(jwtTokenValues.length > 0){ String value = new String(base64Url.decode(jwtTokenValues[0].getBytes())); System.out.println("JWT Header : " + value); JSONParser parser = new JSONParser(); try { jsonHeaderObject = (JSONObject) parser.parse(value); } catch (Exception e) { e.printStackTrace(); } } if(jwtTokenValues.length > 1){ String value = new String(base64Url.decode(jwtTokenValues[1].getBytes())); System.out.println("JWT Body : " + value); jwtAssertion = jwtTokenValues[0] + "." + jwtTokenValues[1]; JSONParser parser = new JSONParser(); try { jsonClaimObject = (JSONObject) parser.parse(value); } catch (Exception e) { e.printStackTrace(); } } if(jwtTokenValues.length > 2){ jwtSignature = base64Url.decode(jwtTokenValues[2].getBytes()); } KeyStore keyStore = null; String thumbPrint = new String(base64Url.decode(((String) jsonHeaderObject.get("x5t")).getBytes())); String signatureAlgo = (String) jsonHeaderObject.get("alg"); if("RS256".equals(signatureAlgo)){ signatureAlgo = "SHA256withRSA"; } else if("RS515".equals(signatureAlgo)){ signatureAlgo = "SHA512withRSA"; } else if("RS384".equals(signatureAlgo)){ signatureAlgo = "SHA384withRSA"; } else { // by default signatureAlgo = "SHA256withRSA"; } if(jwtAssertion != null && jwtSignature != null) { try { keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(new FileInputStream(trustStore), trustStorePassword.toCharArray()); String alias = getAliasForX509CertThumb(thumbPrint.getBytes(), keyStore); Certificate certificate = keyStore.getCertificate(alias); Signature signature = Signature.getInstance(signatureAlgo); signature.initVerify(certificate); signature.update(jwtAssertion.getBytes()); return signature.verify(jwtSignature); } catch (Exception e) { e.printStackTrace(); } } else { System.err.println("Signature is null"); } return false; } private String getAliasForX509CertThumb(byte[] thumb, KeyStore keyStore) { Certificate cert = null; MessageDigest sha = null; try { sha = MessageDigest.getInstance("SHA-1"); for (Enumeration e = keyStore.aliases(); e.hasMoreElements();) { String alias = (String) e.nextElement(); Certificate[] certs = keyStore.getCertificateChain(alias); if (certs == null || certs.length == 0) { cert = keyStore.getCertificate(alias); if (cert == null) { return null; } } else { cert = certs[0]; } sha.update(cert.getEncoded()); byte[] data = sha.digest(); if (new String(thumb).equals(hexify(data))) { return alias; } } } catch (Exception e) { e.printStackTrace(); } return null; } private String hexify(byte bytes[]) { char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; StringBuilder buf = new StringBuilder(bytes.length * 2); for (byte aByte : bytes) { buf.append(hexDigits[(aByte & 0xf0) >> 4]); buf.append(hexDigits[aByte & 0x0f]); } return buf.toString(); } public JSONObject getJsonHeaderObject() { return jsonHeaderObject; } public JSONObject getJsonClaimObject() { return jsonClaimObject; } public static void main(String[] args){ // sample JWT from WSO2IS String jwtToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJTSEEyNTZ3aXRoUlNBIiwieDV0IjoiTm1KbU9HVXhNelpsWWpNMlpEUmhOVFpsWVRBMVl6ZGhaVFJpT1dFME5XSTJNMkptT1RjMVpBIn0.eyJpc3MiOiJodHRwOi8vd3NvMi5vcmcvZ2F0ZXdheSIsImV4cCI6MTQyNjczODI1MDkzNSwiaHR0cDovL3dzbzIub3JnL2dhdGV3YXkvc3Vic2NyaWJlciI6ImFkbWluIiwiaHR0cDovL3dzbzIub3JnL2dhdGV3YXkvYXBwbGljYXRpb25uYW1lIjoiT3BlbmlkQ29ubmVjdCIsImh0dHA6Ly93c28yLm9yZy9nYXRld2F5L2VuZHVzZXIiOiJhc2VsYUBjYXJib24uc3VwZXIiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy9jb3VudHJ5IjoiVW5pdGVkIFN0YXRlcyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2VtYWlsYWRkcmVzcyI6ImFzZWxhQHNvYXNlY3VyaXR5Lm9yZyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2Z1bGxuYW1lIjoiYXNlbGEiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy9naXZlbm5hbWUiOiJBc2VsYSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL2xhc3RuYW1lIjoiUGF0aGJlcml5YSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL29yZ2FuaXphdGlvbiI6InNvYXNlY3VyaXR5Lm9yZyIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL3JvbGUiOiJJbnRlcm5hbC9ldmVyeW9uZSIsICJodHRwOi8vd3NvMi5vcmcvY2xhaW1zL3Nob3ciOiJVbml0ZWQgU3RhdGVzIiwgImh0dHA6Ly93c28yLm9yZy9jbGFpbXMvc3R1ZGlvIjoiQXNlbGEiLCAiaHR0cDovL3dzbzIub3JnL2NsYWltcy90ZWxlcGhvbmUiOiIrOTQ3Nzc2MjU5MzMifQ.d57VGVAhZmTpIMl8hiIUO8D7hAZl-bZm5TnDW9si3qnHFliMHsxlE6HJ7bSjmoobIgdqJ7xToWtOm2orrQKFxzF4xxkpNeU1-qGFoG6-IyRF-JAJao0xq6WIGk8fR2BSN_zxsNbR84-3FMWd6mljPnImWYLe_8mOBFyDcsuDCkk"; SimpleJWTProcessor processor = new SimpleJWTProcessor(jwtToken); if(processor.isValid()){ JSONObject body = processor.getJsonClaimObject(); // retrieve claims String email = (String) body.get("http://wso2.org/claims/emailaddress"); System.out.println("Email : " + email); } else { System.err.println("Signature verification failed."); } } }
Thanks for reading….!!!