Spring User Management API is a secure, production-oriented REST API for user management built with Java 21 and Spring Boot 4.1.0.
The API provides:
- π JWT authentication with Access & Refresh Tokens
- π₯ Role-based authorization
- π Pagination & filtering
- π OpenAPI / Swagger documentation
- π PostgreSQL database
- ποΈ Flyway database migrations
- π³ Docker & Docker Compose
- π§ͺ Unit, security & integration testing
- βοΈ GitHub Actions CI
- π Qodana code quality analysis
The project follows a layered architecture and focuses on security, maintainability, testing, and clean separation of responsibilities.
- User registration
- User login
- JWT Access Token
- JWT Refresh Token
- Refresh token persistence
- Current authenticated user endpoint
- Get current user
- List users
- Pagination
- Email filtering
- User deletion
- Admin-only user management
Two roles are available:
USER
ADMIN
USER provides standard authenticated access, while ADMIN provides elevated access to administrative endpoints.
- Global exception handling
- Custom exceptions
- Validation error responses
- Appropriate HTTP status codes
The project includes:
- OpenAPI
- Swagger UI
- OpenAPI JSON specification
Spring Boot Actuator provides application health checks.
| Technology | Purpose |
|---|---|
| β Java 21 | Programming language |
| π Spring Boot 4.1.0 | Application framework |
| π Spring Security | Authentication & authorization |
| ποΈ Spring Data JPA | Data access |
| π PostgreSQL 16 | Relational database |
| ποΈ Flyway | Database migrations |
| π« JJWT 0.12.6 | JWT authentication |
| β Jakarta Bean Validation | Request validation |
| π springdoc-openapi | OpenAPI / Swagger |
| β€οΈ Spring Boot Actuator | Health & monitoring |
| π§© Lombok | Boilerplate reduction |
| π¦ Maven | Build tool |
| π§ͺ JUnit 5 | Unit testing |
| π§ͺ Mockito | Mock-based testing |
| π MockMvc | Controller & security testing |
| π³ Docker | Containerization |
| π Docker Compose | Multi-container environment |
| βοΈ GitHub Actions | CI |
| π Qodana | Static code analysis |
The application follows a classic layered architecture:
βββββββββββββββββββββββ
β Client β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Controller β
β REST Endpoints β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Service β
β Business Logic β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Repository β
β Spring Data JPA β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β PostgreSQL DB β
βββββββββββββββββββββββ
| Layer | Responsibility |
|---|---|
| Controller | HTTP request & response handling |
| Service | Business logic |
| Repository | Database access |
| Entity | JPA entities |
| DTO | Request & response models |
| Security | JWT & authentication |
| Exception | Centralized error handling |
| Migration | Flyway database migrations |
| Config | Application configuration |
Package root:
com.example.usermanagement
Authentication is implemented using JWT.
| Token | Lifetime | Storage |
|---|---|---|
| π Access Token | 15 minutes | Stateless JWT |
| β»οΈ Refresh Token | 7 days | PostgreSQL |
Protected endpoints require:
Authorization: Bearer <access_token>ββββββββββββ
β Login β
ββββββ¬ββββββ
β
βΌ
ββββββββββββββββββββ
β Access + Refresh β
β Tokens β
ββββββ¬ββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β Protected API β
β Bearer Token β
ββββββ¬ββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β JWT Filter β
ββββββ¬ββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β Spring Security β
ββββββββββββββββββββ
Standard authenticated access.
Elevated privileges including:
- Admin user listing
- User deletion
- Admin dashboard
Role-based access is enforced at the endpoint level through Spring Security.
| Method | Endpoint | Authentication | Description |
|---|---|---|---|
POST |
/api/auth/register |
π Public | Register a new user |
POST |
/api/auth/login |
π Public | Authenticate and receive tokens |
POST |
/api/auth/refresh |
π Public | Get a new access token |
GET |
/api/users/me |
π User | Get current user |
GET |
/api/users |
π User | Paginated user listing |
GET |
/api/users/admin |
π Admin | Admin user listing |
DELETE |
/api/users/{id} |
π Admin | Delete user |
GET |
/api/admin/dashboard |
π Admin | Admin dashboard |
GET |
/actuator/health |
π Public | Health check |
The examples below use HTTPie.
http POST :8080/api/auth/register \
email=jolia@example.com \
password=password123 \
firstName=Jolia \
lastName=Examplehttp POST :8080/api/auth/login \
email=jolia@example.com \
password=password123http POST :8080/api/auth/refresh \
refreshToken="YOUR_REFRESH_TOKEN"http GET :8080/api/users/me \
"Authorization: Bearer YOUR_ACCESS_TOKEN"http GET :8080/api/users \
"Authorization: Bearer YOUR_ACCESS_TOKEN"http GET :8080/api/admin/dashboard \
"Authorization: Bearer YOUR_ACCESS_TOKEN"http DELETE :8080/api/users/1 \
"Authorization: Bearer YOUR_ACCESS_TOKEN"The user listing supports pagination and optional email filtering.
http GET ":8080/api/users?page=0&size=10" \
"Authorization: Bearer YOUR_ACCESS_TOKEN"http GET ":8080/api/users?email=jolia@example.com" \
"Authorization: Bearer YOUR_ACCESS_TOKEN"The API provides centralized error handling through:
GlobalExceptionHandler
Custom exceptions include:
UserAlreadyExistsException
UserNotFoundException
Validation errors are returned in a consistent structure with appropriate HTTP status codes.
The project includes several levels of testing.
AuthServiceTest
UserServiceTest
AuthControllerTest
UserControllerSecurityTest
UserAdminControllerSecurityTest
AdminControllerSecurityTest
AuthUserIntegrationTest
The project also includes an application context test.
./mvnw clean testThe application and PostgreSQL database can be started together using Docker Compose.
docker compose up -d| Service | Address |
|---|---|
| π API | localhost:8080 |
| π PostgreSQL | localhost:5432 |
Inside the Docker network, the application connects to PostgreSQL through:
postgres
Once the application is running:
http://localhost:8080/swagger-ui/index.html
http://localhost:8080/v3/api-docs
Check application health:
curl http://localhost:8080/actuator/healthExpected response:
{
"status": "UP"
}The repository includes GitHub Actions workflows.
| Workflow | Purpose |
|---|---|
ci.yml |
Run tests on every push and pull request |
qodana_code_quality.yml |
Static code analysis with Qodana |
src/main/java/com/example/usermanagement
β
βββ config/
β βββ JpaConfig.java
β βββ OpenApiConfig.java
β
βββ controller/
β βββ admin/
β βββ auth/
β βββ user/
β
βββ dto/
β βββ auth/
β βββ error/
β βββ user/
β
βββ entity/
β βββ enums/
β βββ AuditLog.java
β βββ BaseEntity.java
β βββ RefreshToken.java
β βββ Role.java
β βββ User.java
β
βββ exception/
β βββ GlobalExceptionHandler.java
β βββ UserAlreadyExistsException.java
β βββ UserNotFoundException.java
β
βββ mapper/
β
βββ repository/
β βββ RefreshTokenRepository.java
β βββ RoleRepository.java
β βββ UserRepository.java
β
βββ security/
β βββ config/
β βββ jwt/
β βββ service/
β βββ user/
β
βββ service/
β βββ AuthService.java
β βββ RefreshTokenService.java
β βββ UserService.java
β
βββ util/
βββ validation/
β
βββ SpringUserManagementApiApplication.java
Before running the project, make sure you have:
- β Java 21
- π³ Docker & Docker Compose
- π¦ Maven Wrapper
The repository already includes the Maven Wrapper.
Clone the repository:
git clone https://github.com/ooam-iroo/Spring-User-Management-API.gitEnter the project:
cd Spring-User-Management-APIStart the application:
docker compose up -dThe API will be available at:
http://localhost:8080
Start PostgreSQL locally or use the PostgreSQL service provided by Docker.
./mvnw clean package./mvnw spring-boot:runhttp://localhost:8080/swagger-ui/index.html
Important settings from application.yml:
| Property | Default | Description |
|---|---|---|
spring.datasource.url |
jdbc:postgresql://localhost:5432/user_management |
Database connection |
spring.jpa.hibernate.ddl-auto |
validate |
Schema validation |
spring.flyway.enabled |
true |
Flyway migrations |
app.jwt.secret |
Change in production | JWT signing key |
app.jwt.access-token-expiration |
900000 |
Access token lifetime |
app.jwt.refresh-token-expiration |
604800000 |
Refresh token lifetime |
server.port |
8080 |
Application port |
β οΈ Never use a default or exposed JWT secret in a production environment.
When running with Docker Compose, the database connection is configured to use the PostgreSQL service name:
postgres
The following features are planned but are not implemented yet:
- Redis for token blacklisting / caching
- Rate limiting
- Email verification
- Password reset flow
- Full audit logging
- Testcontainers for integration tests
- Kubernetes deployment manifests
License is not yet defined for this project.