A Spring Boot authentication service that provides JWT-based user authentication and authorization with refresh token support.
This is a Spring Boot 3.5.x application built with Java 17 that implements stateless JWT authentication. The service uses MySQL for data persistence and provides REST endpoints for user registration, authentication, and token management.
Authentication Layer
JwtAuthFilter: Custom servlet filter that intercepts requests and validates JWT tokensSecurityConfig: Spring Security configuration with stateless session managementJwtService: Handles JWT token creation, parsing, and validation using HMAC SHA-256
Service Layer
UserDetailsServiceImpl: Implements Spring Security's UserDetailsService for user authenticationRefreshTokenService: Manages refresh token lifecycle and validationCustomUserDetails: Custom implementation of Spring Security's UserDetails interface
Data Layer
UserInfo: User entity with many-to-many relationship to rolesUserRole: Role entity for role-based access controlRefreshToken: Token entity with one-to-one relationship to users
- Framework: Spring Boot 3.5.6
- Security: Spring Security 3.5.6 with JWT (io.jsonwebtoken 0.12.3)
- Database: MySQL with Spring Data JPA
- Build Tool: Gradle 8.5
- Testing: Spock Framework 2.2 with JUnit 5.10.0
- Language: Java 17 with Groovy support
- Additional: Lombok 1.18.30, Spring Boot Actuator
- User registration with BCrypt password encoding
- Username/password authentication returning JWT access token and refresh token
- Token refresh mechanism for obtaining new access tokens
- Role-based authorization with Spring Security integration
- Access Tokens: 1-minute expiration time with user claims
- Refresh Tokens: 10-minute expiration time stored in database
- Token Validation: Signature verification and expiration checking
- Token Revocation: Refresh tokens removed from database when expired
// JWT token generation with configurable expiration
private String createToken(Map<String, Object> claims, String username) {
return Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis()+1000*60*1))
.signWith(getSignKey(), SignatureAlgorithm.HS256).compact();
}// Security filter chain configuration
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthFilter jwtAuthFilter) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable).cors(CorsConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/v1/login", "/auth/v1/refreshToken", "/auth/v1/signup").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(authenticationProvider())
.build();
}The application uses three main tables:
users table
user_id(Primary Key): String UUIDusername: Unique usernamepassword: BCrypt hashed password
user_roles table
role_id(Primary Key): Auto-generated longname: Role name
user_roles mapping table
- Many-to-many relationship between users and roles
tokens table
id(Primary Key): Auto-generated integertoken: UUID string for refresh tokenexpiry_date: Token expiration timestampuser_id(Foreign Key): References users table
User registration endpoint that creates a new user account.
Request Body: UserInfoDto with username, password, and optional fields Response: JWT access token and refresh token Status Codes: 200 (success), 400 (user exists), 500 (server error)
User authentication endpoint for existing users.
Request Body: AuthRequestDTO with username and password Response: JWT access token and refresh token Status Codes: 200 (success), 500 (authentication failed)
Token refresh endpoint for obtaining new access tokens.
Request Body: RefreshTokenRequestDTO with refresh token Response: New JWT access token with same refresh token Status Codes: 200 (success), Runtime exception for invalid tokens
# Database configuration
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/authservice?useSSL=false&useUnicode=yes&characterEncoding=UTF-8&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=password
# JPA configuration
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# Server configuration
server.port=9898
# Security debugging
logging.level.org.springframework.security=DEBUG- Java 17 or higher
- MySQL 8.0 database
- Gradle 8.5 (or use included wrapper)
# Using Gradle wrapper
./gradlew bootRun
# Or build and run JAR
./gradlew build
java -jar app/build/libs/app.jar- Create MySQL database named
authservice - Configure database credentials in
application.properties - Application will auto-create tables on startup with
spring.jpa.hibernate.ddl-auto=create
The project includes Spock Framework setup for behavior-driven testing:
Dependencies:
- Spock Core 2.2 for Groovy-based testing
- JUnit 5.10.0 for Java testing support
- JUnit Platform Launcher for test execution
Test Structure:
- Test classes located in
app/src/test/groovy/authservice/ - Currently includes basic
AppTest.groovytemplate
Implemented Security Measures:
- BCrypt password hashing with default strength
- JWT token signature validation
- Stateless authentication (no server sessions)
- CORS disabled for security
- CSRF protection disabled for API usage
Configuration Notes:
- JWT secret key is hardcoded in source code
- Debug logging enabled for Spring Security
- Database credentials in plain text configuration
- Very short token expiration times (1 minute access, 10 minute refresh)
Code Organization:
- Controllers handle HTTP requests and responses
- Services contain business logic
- Repositories provide data access layer
- DTOs for request/response data transfer
- Entities represent database tables
Key Design Patterns:
- Repository pattern for data access
- DTO pattern for API data transfer
- Builder pattern for response objects
- Dependency injection throughout application layers
Lombok Usage:
@Datafor getter/setter generation@NoArgsConstructorand@AllArgsConstructorfor constructors@Builderfor builder pattern implementation
The application includes Spring Boot Actuator for basic monitoring capabilities:
- Health endpoints
- Application metrics
- Configuration properties exposure