-
v1.2.0 - Auth and Users Stable
released this
2026-05-08 22:15:20 +02:00 | 276 commits to main since this releasev1.2.0 - Auth and Users
Release Date: 2026-05-08
Milestone: v1.2.0 (Auth and Users)
This milestone delivers a complete authentication and user management system with modern password hashing and JWT-based stateless authentication. All API endpoints now require authentication, providing a secure foundation for multi-user platform access.
Added
User Management with Argon2id Password Hashing
- PasswordHashingService using Argon2id algorithm for secure password storage
- 64MB memory requirement (m=65536)
- 3 iterations (t=3)
- Parallelism factor of 1 (p=1)
- Argon2id variant for resistance to both GPU cracking attacks and side-channel attacks
- Bouncy Castle provider (bcprov-jdk18on 1.78.1) for Argon2 implementation
- Constant-time hash comparison to prevent timing attacks
- PHC string format:
$argon2id$v=19$m=65536,t=3,p=1$[salt]$[hash]
User CRUD APIs
-
UserController REST endpoints:
GET /api/users- List all usersGET /api/users/{id}- Get user by IDPOST /api/users- Create new user with password hashingPATCH /api/users/{id}- Update user (username, email, role)PATCH /api/users/{id}/password- Change user passwordDELETE /api/users/{id}- Delete user
-
UserService enhancements:
create(user, plainPassword)- Hash password and create userupdate(id, updates)- Update user with change trackingupdatePassword(id, newPlainPassword)- Securely change password- Username and email uniqueness validation
- Structured logging for all user operations (create, update, password change, delete)
- Change tracking for user updates (before/after values logged)
-
DTOs:
UpdatePasswordRequest- Password change request validationUpdateUserRequest- User update with email and role validation
JWT Infrastructure
-
JJWT library version 0.12.6 for JWT token management
- jjwt-api - JWT API
- jjwt-impl - JWT implementation
- jjwt-jackson - Jackson integration for JSON serialization
-
JwtService for token generation and validation:
generateAccessToken(userId, username, role)- Create short-lived access tokengenerateRefreshToken(userId)- Create long-lived refresh tokenparseToken(token)- Parse and validate JWT claimsisTokenValid(token)- Check token validity and expiration- Extract userId, username, role, and token type from tokens
- Access tokens valid for 15 minutes (configurable via
jwt.access-token-validity-ms) - Refresh tokens valid for 7 days (configurable via
jwt.refresh-token-validity-ms) - Tokens signed with HS256 (HMAC-SHA256) algorithm
- JWT secret configurable via
jwt.secretproperty (MUST change in production)
-
Token Claims:
sub(subject) - User IDusername- Usernamerole- User role (OWNER, ADMIN, USER, VIEWER)type- Token type (access or refresh)iat- Issued at timestampexp- Expiration timestamp
Authentication Endpoints
-
AuthenticationService:
login(username, password)- Authenticate user and generate tokensrefreshToken(refreshToken)- Generate new access token from refresh token- Password verification using PasswordHashingService
- Structured logging for login attempts (success and failure)
- Structured logging for token refresh operations
- BadCredentialsException for invalid credentials or tokens
-
AuthenticationController REST endpoints:
POST /api/auth/login- User login with username and passwordPOST /api/auth/refresh- Refresh access token using refresh token
-
DTOs:
LoginRequest- Login credentials validationRefreshTokenRequest- Refresh token validationAuthenticationResponse- Login/refresh response with tokens and user info
JWT Authentication and Authorization
-
JwtAuthenticationFilter:
- Extracts JWT from
Authorization: Bearer <token>header - Validates token signature and expiration
- Only accepts access tokens (rejects refresh tokens)
- Populates Spring Security context with user information
- Creates
UsernamePasswordAuthenticationTokenwith user ID as principal - Attaches
JwtAuthenticationDetailswith userId, username, and role - Grants
ROLE_<role>authority for role-based authorization - Silently skips authentication for invalid/expired tokens (401 returned by framework)
- Extracts JWT from
-
SecurityContextHelper utility:
getCurrentUserId()- Get current authenticated user IDgetCurrentUsername()- Get current authenticated usernamegetCurrentUserRole()- Get current authenticated user roleisAuthenticated()- Check if user is authenticatedhasRole(role)- Check if user has specific role
-
SecurityConfig enhancements:
- CSRF protection disabled (stateless JWT authentication)
- Stateless session management
- Method-level security enabled with
@EnableMethodSecurity - Public endpoints:
/api/auth/**,/api/health,/actuator/** - All other
/api/**endpoints require authentication - JWT filter registered before
UsernamePasswordAuthenticationFilter
Security Features
-
Role-Based Access Control:
- User roles: OWNER, ADMIN, USER, VIEWER
- Spring Security authorities with
ROLE_prefix - Method security annotations supported:
@PreAuthorize,@Secured,@RolesAllowed
-
Security Logging:
- Login success and failure events
- Token refresh events
- User creation, updates, password changes, deletion
- Failed login attempts logged with reason for security monitoring
Changed
-
BREAKING CHANGE: All API endpoints now require authentication except:
/api/auth/**- Authentication endpoints/api/health- Health check endpoint/actuator/**- Spring Boot Actuator endpoints
-
User Management: All user operations now use Argon2id instead of BCrypt
- Existing BCrypt hashes incompatible (users must reset passwords)
Security Notes
-
Production Deployment:
- MUST change
jwt.secretproperty in production (default is for development only) - Recommended JWT secret length: at least 256 bits (32 characters) for HS256
- Consider using environment variables for secret management
- MUST change
-
Token Security:
- Access tokens are short-lived (15 minutes) to limit exposure window
- Refresh tokens are long-lived (7 days) but minimal (only userId and type)
- Only access tokens contain sensitive claims (username, role)
- Tokens are stateless - no server-side session storage required
-
Password Security:
- Argon2id with 64MB memory makes brute-force attacks computationally expensive
- Constant-time comparison prevents timing attack exploitation
- Salt is randomly generated per password (16 bytes)
- Hash output is 32 bytes
Configuration
New configuration properties:
jwt: secret: "CHANGE_ME_IN_PRODUCTION_THIS_MUST_BE_AT_LEAST_256_BITS_LONG_FOR_HS256" access-token-validity-ms: 900000 # 15 minutes refresh-token-validity-ms: 604800000 # 7 daysMigration Guide
For API Clients
All API requests (except auth endpoints) now require authentication:
# 1. Login to get tokens curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "password"}' # Response: {"accessToken": "...", "refreshToken": "...", "userId": "...", "username": "admin", "role": "ADMIN"} # 2. Use access token for authenticated requests curl http://localhost:8080/api/users \ -H "Authorization: Bearer <accessToken>" # 3. Refresh access token when expired curl -X POST http://localhost:8080/api/auth/refresh \ -H "Content-Type: application/json" \ -d '{"refreshToken": "<refreshToken>"}'For Developers
Access current user in Spring components:
@Service public class MyService { private final SecurityContextHelper securityHelper; public void myMethod() { UUID userId = securityHelper.getCurrentUserId(); String username = securityHelper.getCurrentUsername(); String role = securityHelper.getCurrentUserRole(); if (securityHelper.hasRole("ADMIN")) { // Admin-only logic } } }Use method security annotations:
@PreAuthorize("hasRole('ADMIN')") public void adminOnlyMethod() { // Only ADMIN role can call this } @PreAuthorize("hasAnyRole('ADMIN', 'OWNER')") public void privilegedMethod() { // ADMIN or OWNER can call this }Technical Details
-
Dependencies:
- Spring Boot Starter Security 4.0.0
- JJWT 0.12.6 (jjwt-api, jjwt-impl, jjwt-jackson)
- Bouncy Castle bcprov-jdk18on 1.78.1
-
Database Schema: Uses existing
userstable from v1.0.0password_hashcolumn stores Argon2id hashes in PHC format
-
Logging: All authentication and user management operations logged to
system_logstable- Categories: AUTH, API
- Events: USER_CREATED, USER_UPDATED, PASSWORD_UPDATED, USER_DELETED, LOGIN_SUCCESS, LOGIN_FAILED, TOKEN_REFRESHED
Included Patches
This milestone includes development patches v1.0.7-dev through v1.0.10-dev:
- v1.0.7-dev: User CRUD with password hashing (initially BCrypt)
- v1.0.8-dev: JWT infrastructure (JwtService, AuthenticationService)
- v1.0.9-dev: Switch from BCrypt to Argon2id
- v1.0.10-dev: JWT authentication filter and authorization enforcement
Known Limitations
- Single JWT secret for all tokens (consider key rotation in future)
- No token revocation mechanism (tokens valid until expiration)
- No password complexity requirements enforced (validation in future)
- No rate limiting on login attempts (future enhancement)
- No account lockout after failed login attempts (future enhancement)
Next Steps
The next milestone (v1.3.0) will focus on Model Providers, implementing:
- Model provider registry and configuration
- Ollama provider integration
- OpenAI provider integration
- Anthropic provider integration
- Provider health checks and fallback mechanisms
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- PasswordHashingService using Argon2id algorithm for secure password storage