JWT verify using public key

Verify the jwt token using public key

Disadvantes of Secret based JWT tokens

A disadvantage of the HS256 algorithm is that the secret key needs to be accessible both when generating and validating tokens.

For a monolithic application, this isn’t so much of a problem, but if you have a distributed system built out of multiple services running independently of each other or same cloud environment having multiple application nodes, you basically have two options.

  • store key into each of the service. This increases the risk of the secret being compromised

  • Have auth server generate and Verify the token. But this pura load on the auth server as it becomes the bottleneck for each request.

JSON Web Key Set

The jwt token is signed using private key. The auth server provides the public key publicly on a url in the form of JSON Web Key Set(JWKS). During verification the public keys are fetched.

Here is an example of JWKS.

{
  "keys": [
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "public:c424b67b-fe28-45d7-b015-f79da50b5b21",
      "alg": "RS256",
      "n": "sttddbg-_yjXzcFpbMJB1fIFam9lQBeXWbTqzJwbuFbspHMsRowa8FaPw44l2C9Q42J3AdQD8CcNj2z7byCTSC5gaDAY30xvZoi5WDWkSjHblMPBUT2cDtw9bIZ6FocRp46KaKzeoVDv3a0EBg5cdAdrefawfZoruPZCLmyLqXZmBM8RbpYLChb-UFO25i7e4AoRJ2hNFYg0qM-hRZNwLliDfkafjnOgSu7_w0WDInNzbUuy26rb_yDNGEIylXHlt0BKcMoeO3sJEwS5EDAkXkvz_7zQ6lgDQ4OLihC4QDwkp7dV2iQxvd7D-XEaSIahiqdHlqR8cUYOJANDVRIufAzzkyK8Shu_MXhVUW7hH3hNjlEh198bCWANHcsZWF2_V78Rl-UzCjsAFWtttf6FYpR9Kt-8ILM3aAYTAk3OwsvzSeqTtWLHp96QE8Bcm1AmZfPWzsd3PpLuSM_wfx4oxDWhdaKQ-HK1hCYLNv2Vity2uNC_tbGxOD9syRujWKS6wFf2b3jFEudV0NUXQ_1Beu8Ir0jHzuA_0D22wgiaSJ9svfpJ7XyoD6fxyHSyhpMsXIDLmnwOPKmD67MFQ7Bv_9H91KZmr34oeh6PVWEwb4wUAkDaCebo6h0gdMoDfZTq9Gn5S-Aq0-_-fIfyN9qrrQ0E1Q_QDhvqXx8eQ1r9smM",
      "e": "AQAB"
    },
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "public:9b9d0b47-b9ed-4ba6-9180-52fc5b161a3a",
      "alg": "RS256",
      "n": "6f4qEUPMmYAyAQnGQOIx1UkIEVPPt1BnhDH70w3Gq6uYpm4hUyRFiM1oZ4_xB28gTmpR_SJZL31E_yZTLKPwKKsCDyF6YGhFtcyifhsLJc45GW4G4poX8Y34EIYlT63G9vutwNwzistWZZqBm52e-bdUQ7zjmWUGpgkq1GQJZyPz2lvA2bThRqqj94w1hqHSCXuAc90cN-Th0Ss1QhKesud7dIgaJQngjWWXdlPBqNYe1oCI04E3gcWdYRFhKey1lkO0WG4VtQxcMADgCrhFVgicpdYyNVqim7Tf31Is_bcQcbFdmumwxWewT-dC6ur3UAv1A97L567QCwlGDP5DAvH35NmL3w291tUd4q5Vlwz6gsRKqDhUSonISboWvvY2x_ndH1oE2hXYin4WL3SyCyp-De8d59C5UhC8KPTvA-3h_UfcPvz6DRDdNrKyRdKmn9vQQpTP9jMtK7Tks8qKxK4D4pesUmjiNMsVCo8AwJ-9hMd7TXamE9CErfDR7jCQONUMetLnitiM7nazCPXkO5tAhJKzQm1o0HvCVptwaa7MksfViK5YPMcCYc9bD1Uujo-782MXqAzdncu0nGKaJXnIsYB0-tFNiNXjuYFQ8KV5k5-Wnn0kga4CkCHlMU2umR19zFsFwFBdVngOYkCEG46KAgdGDqtj8t4d0GY8tcM",
      "e": "AQAB"
    }
  ]
}

Signature Verification

Before we verify the signature, we need to decode the jwt token to fetch the signature.


String string; //jwt json signature
String jwtMessage; // jwt token 
String publicKeyString;

Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA");
KeyFactory kf = KeyFactory.getInstance("EC");

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyString);

KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(jwtMessage);

boolean result = ecdsaVerify.verify(signature);

https://metamug.com/article/security/sign-verify-digital-signature-ecdsa-java.html#3-receive-and-verify