Generating and Verifying JWT with RSA in Java and Spring Boot
NABIL HARAKAT
Posted on November 1, 2023
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.
Posted on November 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024