Files
ToBePlayed-Auth/readme.md
T
2026-05-11 14:40:54 +02:00

6.2 KiB
Raw Blame History

To Be Played (TBP) - Authentication Service

This is the Authentication and User Management Service for the "To Be Played" project. It acts as the central identity provider, handling user authentication, JWT generation, and profile management for the TBP frontend.

🚀 Tech Stack

  • Language: Java 25
  • Framework: Spring Boot 4.1.x
  • Security: Spring Security & JSON Web Tokens (JWT)
  • Database: PostgreSQL 17
  • Migrations: Flyway
  • Observability: Spring Boot Actuator & Micrometer (Prometheus)
  • Build Tool: Maven Wrapper (mvnw)
  • CI/CD: Gitea Actions (Forgejo)

🏗️ Architecture (Clean Architecture)

The project strictly follows a Domain-Driven / Clean Architecture (Ports & Adapters) approach to ensure high maintainability and testability. The codebase is divided into three main layers to prevent framework lock-in and keep business logic isolated.

Layer Breakdown

  1. API / Web Layer (api)

    • Contains REST endpoints, DTOs (Request/Response records), and Global Exception Handlers.
    • Uses ApiMapper to map between DTOs and Domain Models.
    • Rule: This layer delegates to the Service layer and never accesses persistence directly.
  2. Business / Core Layer (model, service, exception)

    • The heart of the application. Contains pure Java classes (Models) and Business Logic (Services).
    • Throws specific business exceptions (e.g., InvalidCredentialsException).
    • Rule: This layer has no dependencies on the API or Persistence layer. It defines interfaces that the persistence layer must implement.
  3. Persistence Layer (persistence)

    • Handles database operations. Contains JPA Entities (UserEntity), Spring Data Repositories, and the EntityMapper.
    • Implements the interfaces defined in the Domain layer.
    • Rule: Entities never leak into the API layer.

Architectural boundaries are enforced via ArchUnit (src/test/java/auth_service/architecture/ArchitectureTest.java), which runs as part of the standard ./mvnw test quality gate. Abstract test bases live under auth_service.shared.test (AbstractUnitTest, AbstractIntegrationTest, AbstractPersistenceTest, AbstractWebMvcTest, AbstractArchitectureTest).

⚙️ Local Development

Running the application locally is fully automated via Spring Boot's Docker Compose Support.

Prerequisites

  • Java 25 installed
  • Docker & Docker Compose running

How to start

  1. Simply run the application from your IDE (e.g., IntelliJ) via the AuthServiceApplication.java main class.
  2. Spring Boot will automatically detect the compose.yaml and spin up a local PostgreSQL container (tbp_auth_db_local) on port 5432.
  3. Flyway will automatically apply all database migrations located in src/main/resources/db/migration.
  4. The application will be available at http://localhost:8080.

To stop the environment and clean the database volume (if needed):

docker compose down -v

🔐 API Versioning

All API endpoints utilize Query Parameter Versioning to keep URLs clean and manageable. Example: GET /api/users/me?v=1

🐳 CI/CD Pipeline

The project uses Gitea Actions for Continuous Integration and Deployment.

Quality Gate: Runs ./mvnw clean verify to ensure tests and builds pass.

Docker Build: Packages the application using a multi-stage Dockerfile.

Registry: Pushes the lightweight Alpine-based image to the private Gitea container registry (git.andreas-dahm.eu/lobo_corp/tbp-auth-service:latest).

📈 Observability

Metrics and health checks are exposed out-of-the-box via Spring Boot Actuator:

Health: http://localhost:8080/actuator/health

Prometheus Metrics: http://localhost:8080/actuator/prometheus

🗺️ Roadmap / Open Topics

Tracking known work that is not yet implemented. Each item is independently actionable.

Security

  • Switch JWT signing from HS256 → EdDSA (Ed25519). Today Auth and Core share a symmetric JWT_SECRET, which means a Core compromise lets an attacker forge tokens. Move to an asymmetric keypair: Auth holds the private key and signs, Core only holds the public key and verifies. jjwt 0.13 supports this via Jwts.SIG.EdDSA; JDK 25 has native Ed25519 KeyFactory. Touches JwtService, JwtConfig, application.yml, JwtServiceTest, and the deployment env vars (JWT_PRIVATE_KEY, JWT_PUBLIC_KEY replace JWT_SECRET). Add a kid header so future rotation is possible.
  • Refresh-token rotation. Current access tokens last 24h with no revocation path. Split into a short-lived (5–15 min) access token and a long-lived (7–30 day) refresh token, rotated on every use, persisted server-side so logout / password change / "log out everywhere" actually revoke. Add a token_version column on users (or a jti blacklist table) checked on each refresh.
  • Move JWT delivery to an httpOnly Secure cookie. Tokens are currently returned in the response body and stored by the frontend in localStorage, exposing them to any XSS payload. Set the cookie server-side, scope it to .tbp.andreas-dahm.eu, and add CSRF protection (Spring Security's CookieCsrfTokenRepository.withHttpOnlyFalse()).
  • Tighten CORS for cookie auth. Restrict allowed origins to https://tbp.andreas-dahm.eu (plus the local dev origin) and set allowCredentials=true. Required before switching to cookie-based JWT.
  • Rate-limit /api/auth/login and /api/registration/**. Currently no brake on credential stuffing or registration spam. Bucket4j or Spring Security's built-in RateLimiter are both options; key by IP + email.

Observability and API

  • Publish a JWKS endpoint (GET /.well-known/jwks.json) once on EdDSA. Lets Core (and any future verifier) fetch the public key automatically and supports key rotation without redeploying every consumer.
  • API versioning review. Query-parameter versioning (?v=1) is unusual; path- or Accept-header-based versioning is more conventional and plays better with HTTP caches. Worth a deliberate decision before more endpoints accumulate.

Testing

  • The abstract test bases under auth_service.shared.test already cover unit / integration / persistence / WebMvc slices. Continue adding controller-level AbstractWebMvcTest coverage for any new endpoint and persistence-layer tests for any new repository.