Generating and Verifying JWT with RSA in Java and Spring Boot
Published: 2023-11-01 09:12:17


**Introduction**
In the world of web applications and microservices, securing data and ensuring user authentication is a paramount concern. JSON Web Tokens (JWTs) have become a popular solution for achieving secure data transmission and authentication. In this article, we will explore how to generate and verify JWTs with RSA in a Java Spring Boot application.

**Technology Stack**
we'll be working with a specific technology stack to generate and verify JWTs using RSA in a Java Spring Boot application. It's important to understand the key components of our stack:

- Java 17
- Spring Boot 3.1.5
- OpenSSL

**What is a JSON Web Token (JWT)?**
JSON Web Tokens, or JWTs, are compact, self-contained data structures that can be used to securely transmit information between parties. They consist of three parts: a header, a payload, and a signature. JWTs are widely used for authentication and data exchange due to their efficiency, scalability, and statelessness.

**The Power of RSA**
RSA (Rivest-Shamir-Adleman) is a widely used public key encryption algorithm. It operates using a pair of keys: a public key used for encryption and a private key used for decryption. RSA's asymmetric nature makes it perfect for securing JWTs, as it allows us to use the public key to validate data signed with the private key.

**Generating a JWT with RSA**
To generate a JWT with RSA in a Java Spring Boot application, you will need the following:
A public key for verifying the JWT signature.
A private key for signing the JWT.
A library such as Bouncy Castle to work with X.509 certificates.

**Exemple to generate a Jwt**
Here's a simplified code snippet demonstrating how to generate a JWT:

```
// Generate a JWT token
	public String createToken(@Nullable Map<String, String> data) throws UnrecoverableKeyException,
			IllegalArgumentException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
		// check inputs
		if (data == null) {
			throw new IllegalArgumentException("Data map is null");
		}
		// Validate inputs
		String subject = data.get("sub");
		if (subject == null || subject.isEmpty()) {
			throw new IllegalArgumentException("Subject is required");
		}

		// Generate random IDs for JWT and header
		String jwtId = UUID.randomUUID().toString();
		String kid = UUID.randomUUID().toString();

		// Calculate the expiration date
		Date validity = calculateExpirationDate();

		// Create a JWT with a set of claims
		Builder builder = JWT.create().withSubject(subject).withIssuer("iss").withAudience("aud").withJWTId(jwtId)
				.withIssuedAt(new Date()).withExpiresAt(validity);

		// Create an Algorithm with the private key
		Algorithm algorithm = Algorithm.RSA256(certService.loadRSAPrivateKey());

		// Create a JWS header with the X.509 certificate and algorithm
		Map<String, Object> headerClaims = Map.of("kid", kid);
		builder.withHeader(headerClaims);

		// Sign the JWT with the private key
		String token = builder.sign(algorithm);

		// Print the JWT token
		log.info("JWT Token: " + token);

		return token;

	}
```

```
// Calculate the expiration date as 2 hours from the current time
private Date calculateExpirationDate() {
  LocalDateTime expirationDateTime = LocalDateTime.now().plusHours(2);
  return Date.from(expirationDateTime.toInstant(ZoneOffset.UTC));
}
```
**Verifying a JWT with RSA**
Verifying a JWT involves validating the signature using a public key. Here's how to verify a JWT in Java Spring Boot:

```
public void verifyToken(Map<String, String> data) throws IllegalArgumentException, KeyStoreException,
    NoSuchAlgorithmException, CertificateException, IOException {
  // check inputs
  if (data == null) {
    throw new IllegalArgumentException("Data map is null");
  }
  // Validate inputs
  String subject = data.get("token");
  if (subject == null || subject.isEmpty()) {
    throw new IllegalArgumentException("Token is required");
  }
  // Define the algorithm and secret key used to sign the JWT
  Algorithm algorithm = Algorithm.RSA256(certService.loadRSAPublicKey());

  // Create a JWTVerifier with the expected algorithm and secret
  JWTVerifier verifier = JWT.require(algorithm).build();

  // Verify the JWT
  try {
    DecodedJWT decodedJWT = verifier.verify(data.get("token"));
    log.info("JWT is valid.");
    log.info("Subject: " + decodedJWT.getSubject());
    log.info("Issuer: " + decodedJWT.getIssuer());
    log.info("Expiration: " + decodedJWT.getExpiresAt());
  } catch (Exception e) {
    log.error("JWT verification failed: " + e.getMessage());
  }

}

```
**Security Considerations**
When working with JWTs and RSA, there are some crucial security considerations:

- Protect Your Keys: Ensure your private key is securely stored and never exposed.
- Token Expiration: Use token expiration to limit the window of opportunity for an attacker.
- Key Rotation: Periodically update your keys and manage key rotation.

**Use Cases**
JWTs with RSA are versatile and find use in various scenarios, including:

- Authenticating users in web applications.
- Securing APIs and microservices.
- Implementing Single Sign-On (SSO) for multiple services.

**Accessing the Source Code**
You can access the source code, along with detailed comments and explanations, by visiting the following GitHub repository:

## https://github.com/nabil-harakat/jwt-service

**Conclusion**
Using JWTs with RSA in a Java Spring Boot application can enhance your data security and authentication mechanisms. With the power of RSA encryption, you can be confident that your data is secure during transmission and that your users are who they claim to be. Implementing JWTs with RSA is a valuable step toward a more secure and trustworthy application.
 Remember to manage your keys carefully, implement token expiration, and stay updated on best practices for using JWTs with RSA to ensure a secure and robust authentication system.