JWT Authentication using RS256 Algorithm in Java
JWT -> Json Web Tokens can be signed using 2 Algorithms
- HS256(Symmetric) → HMAC using SHA256
- RS256(Asymmetric) → RSA using SHA256
HS256 → In HS256 Algorithm only 1 secret key is used to both create and validate JWT Signature.
The secret key is appended to the JWT header and payload by the issuer, and the result is hashed with SHA256 to provide a signature. The recipient recreates the signature using their duplicates of the secret key, JWT header, and payload and compares them to the original.
RS256 → In RS256 Algorithm a pair of public-private keys are used to encrypt and decrypt the data.
The JWT header and payload are hashed by the issuer using SHA256, and they are then encrypted with their private key and the RSA encryption technique. The recipient decrypts the signature ciphertext using their public key before comparing it to a hash they created using a copy of the JWT header and payload to ensure consistency.
In this article we are going to implement JWT Authentication in Java using RS256 algorithm.
Step 1)
Adding JWT dependencies in pom.xml
pom.xml ->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
Step 2)
JwtUtils.java ->
This class consists of all the methods required to create a JWT and Sign it using private key , also verify the signature using public key.
import io.jsonwebtoken.*;
import io.jsonwebtoken.Jwts;
import org.apache.commons.codec.binary.Base64;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.List;
public class JwtUtils {
int accessExpirationMs=9600000;
public String generateAccessToken(String userName, List<String> roleArray,String jwtPrivateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
return Jwts.builder()
.setSubject(userName)
.claim("roles", roleArray)
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + accessExpirationMs))
.signWith(SignatureAlgorithm.RS256, generateJwtKeyEncryption(jwtPrivateKey))
.compact();
}
public PublicKey generateJwtKeyDecryption(String jwtPublicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = Base64.decodeBase64(jwtPublicKey);
X509EncodedKeySpec x509EncodedKeySpec=new X509EncodedKeySpec(keyBytes);
return keyFactory.generatePublic(x509EncodedKeySpec);
}
public PrivateKey generateJwtKeyEncryption(String jwtPrivateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] keyBytes = Base64.decodeBase64(jwtPrivateKey);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec=new PKCS8EncodedKeySpec(keyBytes);
return keyFactory.generatePrivate(pkcs8EncodedKeySpec);
}
public boolean validateJwtToken(String authToken,String jwtPublicKey) {
try {
Jwts.parser().setSigningKey(generateJwtKeyDecryption(jwtPublicKey)).parseClaimsJws(authToken);
return true;
} catch (SignatureException e) {
System.out.println("Invalid JWT signature: {}"+ e.getMessage());
} catch (MalformedJwtException e) {
System.out.println("Invalid JWT token: {}"+ e.getMessage());
} catch (ExpiredJwtException e) {
System.out.println("JWT token is expired: {}"+ e.getMessage());
} catch (UnsupportedJwtException e) {
System.out.println("JWT token is unsupported: {}"+ e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("JWT claims string is empty: {}"+ e.getMessage());
} catch (NoSuchAlgorithmException e) {
System.out.println("no such algorithm exception");
} catch (InvalidKeySpecException e) {
System.out.println("invalid key exception");
}
return false;
}
}
Now we can jump on to create the public-private key pair for creation/validation of JWT
Step 3)
MainClient.java ->
We are creating JWT token with username as “Ajinkya” and role as ADMIN.
You can add other roles like ONBOARDING-USER,SUPPORT-USER etc and configure your UI accordingly.
package org.example;
import org.apache.commons.codec.binary.Base64;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Arrays;
public class MainClient {
public static void main(String[] args) {
try{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
String publicKey = Base64.encodeBase64String(kp.getPublic().getEncoded());
String privateKey = Base64.encodeBase64String(kp.getPrivate().getEncoded());
JwtUtils jwtUtils = new JwtUtils();
String jwtToken = jwtUtils.generateAccessToken("Ajinkya", Arrays.asList("ADMIN"),privateKey);
System.out.println(jwtUtils.validateJwtToken(jwtToken,publicKey));
}catch(Exception e){
e.printStackTrace();
}
}
}
The above program prints “true”
I am also adding Github link for the above project.
Please let me know in the comments if any improvements can be made to this article.
Thank You