A production-ready authentication system using Keycloak as the identity provider and Spring Boot with OAuth2 resource server configuration.
- JWT Authentication - Secure token-based authentication
- Role-based Authorization - USER and ADMIN role management
- Password Reset - Admin-managed password reset functionality
- CORS Support - Cross-origin resource sharing enabled
- Health Monitoring - Spring Boot Actuator endpoints
- Docker Deployment - Containerized with Docker Compose
- Docker and Docker Compose
- Java 21+ (for local development)
- Maven 3.6+ (for local development)
# Copy environment template
cp .env.working .env
# Edit environment variables if needed
nano .env# Start all services
docker-compose up -d
# Check service status
docker-compose ps# Execute test suite
./test.sh- GET /api/public- Public access endpoint
- GET /api/authenticated- Basic authentication check
- GET /api/logout- Logout with Keycloak redirect
- GET /api/user- Requires USER role
- GET /api/admin- Requires ADMIN role
- POST /api/password/reset- Admin password reset
- POST /api/password/change- User password change
- GET /actuator/health- Application health status
- Get Access Token
curl -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=springboot-backend&client_secret=my-client-secret&username=user&password=password"- Use Token in Requests
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8080/api/userKEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin123
KEYCLOAK_ADMIN_USERNAME=admin
POSTGRES_DB=keycloak
POSTGRES_USER=keycloak
POSTGRES_PASSWORD=keycloak123- Admin: admin/admin123(ADMIN role)
- User: user/password(USER role)
# Build application
mvn clean package -DskipTests
# Run locally (requires Keycloak running)
java -jar target/keycloak-springboot-app-0.0.1-SNAPSHOT.jar# Rebuild application container
docker-compose build app --no-cache
docker-compose up -d app┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Frontend      │    │  Spring Boot    │    │   Keycloak      │
│   Application   │◄──►│   Resource      │◄──►│   Identity      │
│                 │    │   Server        │    │   Provider      │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                │                        │
                                ▼                        ▼
                       ┌─────────────────┐    ┌─────────────────┐
                       │   Application   │    │   PostgreSQL    │
                       │   Database      │    │   Database      │
                       └─────────────────┘    └─────────────────┘
- JWT Token Validation - All protected endpoints validate JWT tokens
- Role-based Access Control - Method-level security with @PreAuthorize
- CORS Configuration - Secure cross-origin requests
- Password Encryption - Bcrypt password hashing
- Session Management - Stateless JWT-based sessions
- Service Not Starting
# Check logs
docker-compose logs app
docker-compose logs keycloak- Authentication Failures
# Verify Keycloak is running
curl http://localhost:8081/realms/springboot-realm/.well-known/openid_configuration- Token Issues
# Check token validity
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8080/api/authenticated# Stop and remove all containers
docker-compose down -v
# Restart fresh
docker-compose up -dcurl http://localhost:8080/api/publiccurl -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=springboot-backend&client_secret=my-client-secret&username=user&password=password"curl -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=springboot-backend&client_secret=my-client-secret&username=admin&password=password"# Set your token first
TOKEN="your_access_token_here"
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/authenticatedcurl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/user# Use admin token
ADMIN_TOKEN="your_admin_token_here"
curl -H "Authorization: Bearer $ADMIN_TOKEN" http://localhost:8080/api/admincurl http://localhost:8080/actuator/healthcurl -X POST http://localhost:8080/api/password/reset \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"username": "user", "newPassword": "newpassword123"}'curl -X POST http://localhost:8080/api/password/change \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"currentPassword": "password", "newPassword": "newpassword123"}'# Use refresh token from login response
curl -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token&client_id=springboot-backend&client_secret=my-client-secret&refresh_token=your_refresh_token_here"curl http://localhost:8080/api/logout#!/bin/bash
echo "=== Testing Keycloak Spring Boot API ==="
# Test public endpoint
echo "1. Testing public endpoint..."
curl -s http://localhost:8080/api/public | jq .
# Get user token
echo "2. Getting user token..."
USER_RESPONSE=$(curl -s -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=springboot-backend&client_secret=my-client-secret&username=user&password=password")
USER_TOKEN=$(echo $USER_RESPONSE | jq -r .access_token)
# Test authenticated endpoint
echo "3. Testing authenticated endpoint..."
curl -s -H "Authorization: Bearer $USER_TOKEN" http://localhost:8080/api/authenticated | jq .
# Test user role endpoint
echo "4. Testing user role endpoint..."
curl -s -H "Authorization: Bearer $USER_TOKEN" http://localhost:8080/api/user | jq .
# Get admin token
echo "5. Getting admin token..."
ADMIN_RESPONSE=$(curl -s -X POST http://localhost:8081/realms/springboot-realm/protocol/openid-connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&client_id=springboot-backend&client_secret=my-client-secret&username=admin&password=password")
ADMIN_TOKEN=$(echo $ADMIN_RESPONSE | jq -r .access_token)
# Test admin role endpoint
echo "6. Testing admin role endpoint..."
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" http://localhost:8080/api/admin | jq .
# Test health endpoint
echo "7. Testing health endpoint..."
curl -s http://localhost:8080/actuator/health | jq .
echo "=== All tests completed ==="