A lightweight, production-ready Java library for JWT token management with built-in Redis support, token persistence, and comprehensive validation features.
- Features
- Quick Start
- Core Components
- Usage Examples
- API Reference
- Configuration
- License
- Contributing
- Simple JWT Management: Create, validate, and parse JWT tokens with minimal configuration
- Persistent Storage: Built-in support for in-memory and Redis token storage
- Token Invalidation: Programmatic token revocation with multiple invalidation strategies
- Comprehensive Validation: Check expiration, claims, subjects, and token types
- Flexible Token Parameters: Custom claims, issuance dates, and expiration configurations
- Production Ready: Thread-safe implementations with comprehensive test coverage
- Zero Dependencies: Self-contained with minimal external dependencies (except Redis client)
Maven:
<dependency>
<groupId>io.github.ilyalisov</groupId>
<artifactId>jwt</artifactId>
<version>0.3.0</version>
</dependency>Gradle:
Add to your build.gradle or build.gradle.kts:
implementation("io.github.ilyalisov:jwt:0.3.0")The core interface for JWT operations with two implementations:
TokenServiceImpl - Basic JWT operations without persistence:
String secret = "c29tZWxvbmdzZWNyZXRzdHJpbmdmb3JleGFtcGxlYW5kaXRuZWVkc3RvYmVsb25nDQo=";
TokenService tokenService = new TokenServiceImpl(secret);PersistentTokenServiceImpl - JWT operations with token storage and invalidation:
TokenService tokenService = new PersistentTokenServiceImpl(secret);Flexible storage implementations for different use cases:
- TokenStorageImpl: In-memory storage (default)
- RedisTokenStorageImpl: Redis-backed persistent storage
- Custom implementations: Implement
TokenStorageinterface for custom storage solutions
Builder pattern for configuring JWT tokens:
TokenParameters params = TokenParameters.builder(
"user@example.com", // subject
"access", // token type
Duration.ofHours(1) // expiration
)
.claim("role", "ADMIN") // custom claims
.issuedAt(new Date()) // issuance date
.build();Create a JWT token:
String token = tokenService.create(
TokenParameters.builder(
"user@example.com",
"access",
Duration.ofHours(1)
)
.claim("role", "ADMIN")
.build()
);Validate token expiration:
boolean expired = tokenService.isExpired(token);
// Or with custom validation date
boolean expired = tokenService.isExpired(token, new Date());Check token claims:
boolean hasRole = tokenService.has(token, "role", "ADMIN");Extract token information:
String subject = tokenService.getSubject(token);
String type = tokenService.getType(token);
Map<String, Object> claims = tokenService.claims(token);
Object role = tokenService.claim(token, "role");In-memory storage (default):
PersistentTokenService tokenService = new PersistentTokenServiceImpl(secret);Invalidate tokens:
// Invalidate by token value
boolean deleted = tokenService.invalidate(token);
// Invalidate by subject and type
boolean deleted = tokenService.invalidate(
TokenParameters.builder(
"user@example.com",
"access",
Duration.ZERO
)
.build()
);Basic Redis setup:
TokenStorage tokenStorage = new RedisTokenStorageImpl("localhost", 6379);
PersistentTokenService tokenService = new PersistentTokenServiceImpl(secret, tokenStorage);Advanced Redis configuration:
// With authentication
TokenStorage tokenStorage = new RedisTokenStorageImpl(
"localhost",
6379,
"username",
"password"
);
// With custom Redis key schema
RedisSchema customSchema = (subject, type) -> "app:tokens:" + subject + ":" + type;
TokenStorage tokenStorage = new RedisTokenStorageImpl(
"localhost",
6379,
customSchema
);
// With existing Jedis pool
JedisPool jedisPool = new JedisPool("localhost", 6379);
TokenStorage tokenStorage = new RedisTokenStorageImpl(jedisPool);Complete validation workflow:
public boolean validateToken(String token) {
// Check if token exists (for persistent storage)
if (tokenService instanceof PersistentTokenService) {
if (!((PersistentTokenService) tokenService).exists(token)) {
return false;
}
}
// Validate expiration
if (tokenService.isExpired(token)) {
return false;
}
// Validate required claims
if (!tokenService.has(token, "role", "USER")) {
return false;
}
// Validate token type
if (!"access".equals(tokenService.getType(token))) {
return false;
}
return true;
}| Method | Description | Returns |
|---|---|---|
create(TokenParameters) |
Creates a new JWT token | String |
isExpired(String) |
Checks if token is expired | boolean |
isExpired(String, Date) |
Checks if token was expired at specific date | boolean |
has(String, String, Object) |
Checks if token contains specific claim | boolean |
getSubject(String) |
Extracts subject from token | String |
getType(String) |
Extracts type from token | String |
claims(String) |
Returns all token claims | Map<String, Object> |
claim(String, String) |
Returns specific claim | Object |
| Method | Description | Returns |
|---|---|---|
invalidate(String) |
Invalidates token by value | boolean |
invalidate(TokenParameters) |
Invalidates token by subject and type | boolean |
exists(String) |
Checks if token exists in storage | boolean |
The library requires a Base64-encoded secret string. Generate one using:
import java.util.Base64;
String secret = Base64.getEncoder().encodeToString(
"some-long-secret-string-for-example-and-it-needs-to-be-long".getBytes()
);For production Redis deployments, consider:
- Connection pooling configuration
- SSL/TLS encryption
- Redis cluster support
- Sentinel configuration for high availability
// Short-lived access tokens
Duration accessTokenExpiry = Duration.ofMinutes(30);
// Long-lived refresh tokens
Duration refreshTokenExpiry = Duration.ofDays(7);
// One-time use tokens
Duration oneTimeTokenExpiry = Duration.ofMinutes(10);This project is licensed under the MIT License - see the LICENSE file for details.
We welcome contributions! Please feel free to submit issues and enhancement requests.
To contribute, make a fork and open a pull request. You can find issues here.
Make sure, you follow project's codestyle.