JSON Web Token (JWT) is a widely used mechanism for securely transmitting information between systems.
JWT is commonly used in:
• API authentication
• Single Sign-On (SSO)
• Microservices communication
This article explains:
- What JWT is
- JWT structure
- How encryption and signing works
- How to generate and validate JWT in Java
- A simple diagram explaining the flow
What is JWT?
JWT (JSON Web Token) is a compact, URL-safe token format used to securely transmit information between two parties. Refer RFC7519 .
A JWT contains claims (information) that are digitally signed and optionally encrypted.
JWT tokens are typically used after a user logs in successfully. The server generates a token and sends it back to the client. The client includes this token in future requests for authentication.
JWT Structure
JWT Structure
A JWT consists of three parts separated by dots:
HEADER.PAYLOAD.SIGNATURE
Example JWT:
eyJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJteS5jb21wYW55LmNvbSIsInN1YiI6ImpvaG4uZG9lIiwiaWF0IjoxNzczMTg0MTIwLCJleHAiOjE3NzMxODQ0MjAsImp0aSI6IjI1Y2JkNjVmLTYzODEtNGZiYi05YWMyLTk4ZTk0ZGYwYTI2YSJ9
.
UEG4iZhhtyG58V0Vcz-IHOL8MMPmDVqZdyRhoaTnYCI
Each part is Base64URL encoded. ()
1. Header
The header contains metadata about the token.
Example:
{"alg":"HS256"}
alg indicates the algorithm used to sign the token.
Common algorithms include:
- HS256
- RS256
- ES256
2. Payload
The payload contains claims, which are pieces of information about the user.
Example:
{
"iss":"my.company.com",
"sub":"john.doe","iat":1773184120,
"exp":1773184420,
"jti":"25cbd65f-6381-4fbb-9ac2-98e94df0a26a"}
}
Note:
JWT payload is not encrypted by default. It is only Base64 encoded.
Anyone can decode the payload, but the signature prevents tampering.
3. Signature
The signature ensures the token has not been modified.
Example process:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
If someone modifies the payload, the signature verification will fail.
JWT Authentication Flow
Typical authentication flow:
- User logs in with username and password
- Server validates credentials
- Server generates a JWT
- Client stores the token
- Client sends JWT in Authorization header
- Server verifies the token
Example header in API request:
Authorization: Bearer
Generating JWT in java
(Example Code)
package jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.UUID;
import java.nio.charset.StandardCharsets;
public class JwtTokenGenerator {
/**
* Generates a signed JWT token using a shared secret key.
* @param issuer The issuer of the token.
* @param subject The subject of the token (e.g., user ID).
* @param secretKey The secret key for signing (must be at least 256 bits).
* @return The compact JWT string.
*/
public static String generateJwtToken(String issuer, String subject, String secretKey) {
// Define the key from the secret string
// The key should be securely managed and stored
Key key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
Instant now = Instant.now();
// Build the JWT
String jwt = Jwts.builder()
.setIssuer(issuer) // Set the issuer claim
.setSubject(subject) // Set the subject claim
.setIssuedAt(Date.from(now)) // Set the issued at time
.setExpiration(Date.from(now.plus(5L, ChronoUnit.MINUTES))) // Set expiration for 5 minutes later
.setId(UUID.randomUUID().toString()) // Set a unique ID for the token
.signWith(key) // Sign the JWT with the key
.compact(); // Compacts the JWT into its final string form
return jwt;
}
public static void main(String[] args) {
// Example usage: replace with your actual values
String myIssuer = "my.company.com";
String mySubject = "john.doe";
// Key must be sufficiently long for HS256 (e.g., 32 characters or more for 256 bits)
String mySecretKey = "aVerySecureAndLongSecretKeyForSigningJwts";
String token = generateJwtToken(myIssuer, mySubject, mySecretKey);
System.out.println("Generated JWT Token:");
System.out.println(token);
}
}
The above code will create the token.
Validating JWT in Java
Example Code
package jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
public class JWTValidation {
private static final String SECRET_KEY = "aVerySecureAndLongSecretKeyForSigningJwts";
public static Claims validate(String token) {
return Jwts.parser().verifyWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))).build().parseSignedClaims(token).getPayload();
}
public static void main(String[] args) {
if (args.length < 1 ) {
System.out.println("Please provide the token String as a parameter");
return;
}
String tokenString = args[0];
Claims claims = validate (tokenString);
System.out.println("Subject: " + claims.getSubject());
System.out.println("Issuer: " + claims.getIssuer());
System.out.println("Issued At: " + claims.getIssuedAt());
System.out.println("Expiration: " + claims.getExpiration());
System.out.println("ID: " + claims.getId());
System.out.println("Audience: " + claims.getAudience());
}
}
By running the above code you can pass the generated token to test the validity.
Decoding JWT
Java Example
package jwt;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class JWTTokenDecoder {
public static void decodeJWT(String token) {
String[] parts = token.split("\\.");
if (parts.length != 3) {
throw new IllegalArgumentException("Invalid JWT token format");
}
Base64.Decoder decoder = Base64.getUrlDecoder();
// Decode Header
String header = new String(decoder.decode(parts[0]), StandardCharsets.UTF_8);
System.out.println("JWT Header: " + header);
// Decode Payload (Body)
String payload = new String(decoder.decode(parts[1]), StandardCharsets.UTF_8);
System.out.println("JWT Body: " + payload);
// The signature part (parts[2]) is a hash and cannot be "decoded" into a readable string in the same way.
// It's used for signature verification.
}
public static void main(String[] args) {
if (args.length < 1 ) {
System.out.println("Please provide the token String as a parameter");
return;
}
String jwtToken = args[0];
decodeJWT(jwtToken);
}
}
You can pass the JWT and get the decoded value
JWT Encryption vs Signing
Many developers confuse signing and encryption.
Signing ensures:
• Token integrity
• Token authenticity
Encryption ensures:
• Token confidentiality
Most JWT tokens are signed but not encrypted.
Security Best Practices
When using JWT in production:
- Never store sensitive data in payload
- Always use HTTPS
- Set token expiration (exp claim) Refer: Claims , setExpiration
- Rotate secret keys periodically
- Validate token signature on every request
When Should You Use JWT?
JWT works well when:
- Building stateless APIs
- Implementing microservices authentication
- Creating Single Sign-On systems
- Protecting REST APIs
Source Code
All source files are available on GitHub:
Github source codes
Conclusion
JWT provides a simple and secure way to transmit claims between systems.
Understanding how JWT works internally — including header, payload, and signature — is important when implementing authentication systems in modern applications.
By using proper signing, validation, and expiration strategies, JWT can be a powerful tool for secure API authentication.
Top comments (0)