Skip to content

abhim8/auth-platform

Java Spring Boot License Build Spring WebFlux Spring Security JWT PostgreSQL Redis

Authentication Platform

Centralized authentication service for the API Gateway microservices platform. Provides a provider-based, mechanism-agnostic authentication service that validates credentials and returns verified identity claims.

Project Overview

The Authentication Platform is the centralized identity service for the microservices ecosystem. It authenticates users and API clients, validates credentials on behalf of the API Gateway, manages sessions and refresh tokens, issues JWTs, and provides a unified authentication contract for downstream services. The platform owns authentication concerns while remaining independent of authorization logic in downstream services.

Responsibilities

  • Login - Authenticate users with username/email and password, issue JWT access tokens, refresh tokens, and session cookies
  • Validation - Validate any authentication mechanism (JWT, API Key, Session) forwarded by the API Gateway
  • Token Refresh - Rotate refresh tokens with one-time-use semantics
  • Session Management - Maintain and revoke Redis-backed user sessions
  • API Key Management - Create, list, and revoke API keys for users and API clients
  • Observability - Correlation IDs, structured logging, request timing metrics, health probes
  • Audit Logging - Authentication events logged for security analysis

Out of Scope

The following are intentionally handled by other services or are not yet implemented:

  • Service-to-service authentication (mTLS between Gateway and Auth Platform)
  • OAuth2 / OpenID Connect flows
  • SAML assertion processing
  • Passkeys / WebAuthn
  • User registration, password reset, or account management
  • Kubernetes manifests or deployment runbooks

Key Features

Feature Description
Provider Architecture Pluggable AuthenticationProvider interface with configuration-driven registry
JWT Authentication HMAC-SHA256 signed tokens with configurable key rotation
API Key Authentication Hash-based key lookup, XOR ownership (user or client), lifecycle management
Session Authentication Redis-backed sessions with TTL-based expiration and renewal
Login BCrypt password verification, account status checks, audit logging
Refresh Token Rotation One-time-use tokens with revoke-on-rotate pattern
Logout Single session and bulk session revocation
Database PostgreSQL with Liquibase migrations, JPA entities, seed data
Observability Correlation IDs, JSON logging, Micrometer metrics, health probes
Gateway Contract POST /internal/v1/auth/validate for request-time validation

High-Level Architecture

graph LR

Client --> API-Gateway
API-Gateway --> AuthPlatform

AuthPlatform --> PostgreSQL
AuthPlatform --> Redis

API-Gateway --> Upstream["Microservices"]

subgraph Authentication Platform
    Validation
    Login
    Refresh
    Logout
    ApiKeys
end
Loading

Authentication Flow

sequenceDiagram
    participant C as Client
    participant G as API Gateway
    participant AP as Auth Platform
    participant DB as PostgreSQL
    participant R as Redis

    C->>G: POST /api/login {username, password}
    G->>AP: POST /internal/v1/auth/login
    AP->>DB: Lookup user
    AP->>DB: Verify BCrypt hash
    AP->>DB: Create refresh token
    AP->>AP: Create JWT
    AP->>R: Create session (optional)
    AP-->>G: {accessToken, refreshToken, sessionToken, claims}
    G-->>C: {accessToken, refreshToken, sessionToken, claims}

    C->>G: API request + Authorization: Bearer <JWT>
    G->>AP: POST /internal/v1/auth/validate {headers}
    AP->>AP: Select JWT provider
    AP->>AP: Verify HMAC signature
    AP-->>G: {authenticated: true, claims}
    G->>Upstream: Forward request with identity headers

    C->>G: POST /api/refresh {refreshToken}
    G->>AP: POST /internal/v1/auth/refresh
    AP->>DB: Validate token hash
    AP->>DB: Revoke old token
    AP->>DB: Create new token
    AP->>AP: Create new JWT
    AP-->>G: {accessToken, newRefreshToken}
    G-->>C: {accessToken, newRefreshToken}
Loading

Request Lifecycle (Validation)

sequenceDiagram
    participant G as API Gateway
    participant C as Controller
    participant S as AuthValidationService
    participant R as ProviderRegistry
    participant P as AuthenticationProvider

    G->>C: POST /internal/v1/auth/validate
    C->>C: @Valid + extract correlationId/clientIp/userAgent
    C->>S: validate(request, correlationId, clientIp, userAgent)
    S->>S: Build AuthenticationContext
    S->>R: selectProvider(context)
    R->>R: Filter enabled providers
    R->>R: Find first matching supports()
    R-->>S: AuthenticationProvider
    S->>P: authenticate(context)
    P-->>S: AuthenticationResult
    S->>S: Map to AuthValidationResponse
    S-->>C: Mono<AuthValidationResponse>
    C-->>G: ResponseEntity.ok(response)
Loading

Package Structure

src/main/java/auth/
├── AuthApplication.java                 # Spring Boot entry point
├── config/
│   ├── AuthProperties.java              # @ConfigurationProperties
│   ├── JpaConfig.java                   # JPA auditing configuration
│   ├── RedisConfig.java                 # Conditional ReactiveRedisTemplate
│   └── SecurityConfig.java              # WebFlux security rules
├── controller/
│   ├── AuthValidationController.java    # POST /validate
│   ├── LoginController.java             # POST /login
│   ├── RefreshController.java           # POST /refresh
│   ├── LogoutController.java            # POST /logout, /logout-all
│   └── ApiKeyManagementController.java  # POST/GET/DELETE /api-keys
├── dto/
│   ├── request/
│   │   ├── AuthLoginRequest.java
│   │   ├── AuthValidationRequest.java
│   │   ├── CreateApiKeyRequest.java
│   │   └── RefreshRequest.java
│   └── response/
│       ├── ApiKeyEntry.java
│       ├── AuthLoginResponse.java
│       ├── AuthValidationResponse.java
│       ├── CreateApiKeyResponse.java
│       └── RefreshResponse.java
├── exception/
│   ├── AuthException.java
│   ├── ErrorCode.java                   # AUTH-001 through AUTH-015
│   ├── ErrorResponse.java
│   └── GlobalExceptionHandler.java
├── jwt/
│   └── JwtTokenService.java             # JWT creation & validation
├── model/
│   ├── AuthenticationClaims.java        # Identity claims record
│   ├── AuthenticationContext.java       # Internal auth context
│   └── AuthenticationHeaders.java       # 13 forwarded header fields
├── observability/
│   ├── CorrelationIdFilter.java         # Correlation ID propagation
│   └── RequestTimingFilter.java         # Micrometer request timing
├── persistence/
│   ├── entity/
│   │   ├── ApiClient.java
│   │   ├── ApiKey.java
│   │   ├── AuditLog.java
│   │   ├── Permission.java
│   │   ├── RefreshToken.java
│   │   ├── Role.java
│   │   └── User.java
│   └── repository/
│       ├── ApiClientRepository.java
│       ├── ApiKeyRepository.java
│       ├── AuditLogRepository.java
│       ├── PermissionRepository.java
│       ├── RefreshTokenRepository.java
│       ├── RoleRepository.java
│       └── UserRepository.java
├── provider/
│   ├── AuthenticationProvider.java      # Provider interface
│   ├── AuthenticationProviderRegistry.java
│   ├── AuthenticationResult.java
│   └── impl/
│       ├── ApiKeyAuthenticationProvider.java
│       ├── JwtAuthenticationProvider.java
│       ├── MockAuthenticationProvider.java
│       └── SessionAuthenticationProvider.java
├── service/
│   ├── ApiKeyManagementService.java
│   ├── AuthValidationService.java
│   ├── AuthenticationService.java       # Login orchestration
│   ├── RefreshTokenService.java
│   └── SessionService.java
├── session/
│   └── SessionData.java                 # Session data record
└── util/
    └── CryptoUtils.java                 # SHA-256 + random token generation

Technology Stack

Layer Technology
Language Java 26
Framework Spring Boot 4.1
Reactive Spring WebFlux (Netty)
Security Spring Security WebFlux
JWT Nimbus JOSE + JWT (HMAC-SHA256)
Persistence Spring Data JPA + Hibernate
Database PostgreSQL 16+
ORM Spring Data JPA + Hibernate
Migrations Liquibase (XML changelogs)
Cache Redis 7+
Logging Log4j2 with JSON template layout
Metrics Micrometer
Build Maven 3.9+
Validation Jakarta Bean Validation
Testing JUnit 5, Mockito, AssertJ, Reactor Test

Configuration

Authentication Providers

Property Default Description
auth.providers.mock.enabled true Enable mock provider (development only)
auth.providers.mock.authenticated-by-default true Mock always authenticates
auth.providers.mock.default-subject mock-user Default mock subject
auth.providers.jwt.enabled true Enable JWT Bearer token provider
auth.providers.api-key.enabled true Enable API key provider
auth.providers.session.enabled true Enable session cookie provider

JWT Configuration

Property Default Description
auth.jwt.issuer auth-platform JWT issuer claim
auth.jwt.audience api-gateway JWT audience claim
auth.jwt.access-token-expiration-seconds 3600 Access token TTL (1 hour)
auth.jwt.keys[].id - Signing key identifier
auth.jwt.keys[].secret - Base64-encoded HMAC secret
auth.jwt.keys[].active true Whether this key is used for signing

Refresh Token Configuration

Property Default Description
auth.refresh-token.expiration-seconds 604800 Refresh token TTL (7 days)
auth.refresh-token.length-bytes 32 Random token length (256-bit)

Session Configuration

Property Default Description
auth.session.expiration-seconds 86400 Session TTL (24 hours)
auth.session.token-length-bytes 32 Session token length

Correlation ID

Property Default Description
auth.correlation-id.header-name X-Correlation-ID Header name for correlation ID
auth.correlation-id.generate-if-missing true Auto-generate if not provided

Database

Property Default Description
spring.datasource.url jdbc:postgresql://localhost:5432/auth?currentSchema=auth_platform JDBC URL
spring.datasource.username abhilash Database user
spring.datasource.password (empty) Database password

Redis

Property Default Description
spring.redis.host localhost Redis host
spring.redis.port 6379 Redis port
spring.redis.password (empty) Redis password

Actuator

Property Default Description
management.endpoints.web.exposure.include health,info,metrics Exposed endpoints
management.endpoint.health.probes.enabled true Kubernetes probe support

Running Locally

Prerequisites

  • Java 26 (Temurin recommended)
  • PostgreSQL 16+ - running on localhost:5432 with database auth and schema auth_platform
  • Redis 7+ - running on localhost:6379 (optional for development without sessions)

Database Setup

CREATE DATABASE auth;
\c auth;
CREATE SCHEMA auth_platform;

Build and Test

mvn clean verify

All tests are unit tests and do not require PostgreSQL or Redis.

Run the Application

mvn spring-boot:run

Starts on port 8004 with all providers enabled. Mock provider is the lowest-priority - real providers (JWT, API Key, Session) will match first if their credentials are present.

Verify

# Health check
curl http://localhost:8004/actuator/health

# Validate with mock provider
curl -X POST http://localhost:8004/internal/v1/auth/validate \
  -H 'Content-Type: application/json' \
  -d '{"requestId": "test-1", "headers": {}}'

# Login (requires PostgreSQL with seed data)
curl -X POST http://localhost:8004/internal/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username": "admin", "password": "dev-password"}'

Docker

Build

docker build -t auth-platform .

Run

docker run -p 8004:8004 \
  -e DATABASE_URL=jdbc:postgresql://host.docker.internal:5432/auth?currentSchema=auth_platform \
  -e DATABASE_USERNAME=user \
  -e DATABASE_PASSWORD=password \
  -e REDIS_HOST=host.docker.internal \
  auth-platform

Docker Compose

docker compose up --build

Docker Compose starts only the Authentication Platform. PostgreSQL and Redis must be available externally (see Running Locally for connection details).

Container Networking

When the Authentication Platform runs inside Docker, PostgreSQL and Redis must be reachable from within the container.

Dependency Host Example Docker Example
PostgreSQL localhost host.docker.internal
Redis localhost host.docker.internal

When all services run under Docker Compose, use service names instead.

Authentication Providers

Provider Interface

public interface AuthenticationProvider {
    boolean supports(AuthenticationContext context);
    Mono<AuthenticationResult> authenticate(AuthenticationContext context);
    default String getProviderId() { ... }
}
  • supports() - Determines if this provider can handle the given context
  • authenticate() - Performs authentication and returns a result with claims

Implemented Providers

Provider Enabled By Default Trigger Backend
Mock Yes (development) Always None (in-memory config)
JWT No Authorization: Bearer <token> HMAC-SHA256 verification
API Key No apiKey header PostgreSQL hash lookup
Session No Cookie: session=<token> Redis lookup + renewal

Provider Registry

The AuthenticationProviderRegistry collects all provider beans, filters by enabled configuration, and selects the first provider where supports() returns true. Provider ordering follows Spring bean registration order.

Adding a New Provider

  1. Implement AuthenticationProvider
  2. Annotate with @Component
  3. Add configuration to application.yml under auth.providers.{id}
  4. Register the {id} mapping in AuthenticationProviderRegistry.isProviderEnabled()

No orchestration code changes in services or controllers are required.

Token Lifecycle

Access Tokens (JWT)

  • Format: Signed JWT (HMAC-SHA256) with standard and custom claims
  • Expiration: Configurable (default 1 hour)
  • Validation: Signature verification, expiration check, issuer/audience validation
  • Key Rotation: Multiple keys supported with active/inactive flag - zero-downtime rotation

Refresh Tokens

  • Format: Opaque random token (256-bit), SHA-256 hash stored in database
  • Expiration: Configurable (default 7 days)
  • Rotation: One-time-use - old token revoked, new token issued on each refresh
  • Theft Detection: If a token is used by an attacker, the legitimate client's next refresh will fail

Session Tokens

  • Format: Opaque token prefixed with sess_, stored in Redis
  • Expiration: Configurable TTL (default 24 hours), refreshed on each validation
  • Revocation: Single session or all user sessions

Session Management

  • Storage: Redis with key session:<token> → serialized SessionData
  • User Index: user:sessions:<userId> → set of active session IDs
  • TTL: Configurable, reset on each validated request
  • Serialization: Pipe-delimited with escape/unescape handling
  • Revocation: Single (POST /logout) or bulk (POST /logout-all)

API Key Management

Endpoint Method Description
POST /internal/v1/api-keys Create Creates a new API key (raw key returned once)
GET /internal/v1/api-keys?userId=X List by user Lists keys for a user
GET /internal/v1/api-keys?clientId=X List by client Lists keys for an API client
DELETE /internal/v1/api-keys/{id} Revoke Disables a key
  • Format: ak_<64-hex-chars> (prefix + 32 random bytes)
  • Storage: SHA-256 hash only - raw key is irrecoverable after creation
  • Ownership: XOR - belongs to exactly one User or ApiClient
  • Lifecycle: Created → Used → Expired or Revoked

Refresh Tokens

Endpoint Method Description
POST /internal/v1/auth/refresh Rotate Validates, revokes old, and issues new refresh token + JWT
  • Storage: SHA-256 hash in PostgreSQL (refresh_tokens table)
  • Rotation: Each use revokes the presented token and creates a new one
  • Error Codes: AUTH-011 (not found), AUTH-012 (revoked), AUTH-013 (expired)

Observability

Correlation IDs

The CorrelationIdFilter extracts or generates a correlation ID on every request. It is propagated via:

  • Exchange attributes (accessible throughout the request lifecycle)
  • Response headers (X-Correlation-ID)
  • MDC (for log correlation)

Structured Logging

Log4j2 with JSON template layout. Each log event includes:

  • level, timestamp (ISO-8601), logger, message
  • correlationId, traceId, spanId
  • thread, exception (if applicable)

Metrics

Micrometer metrics are exposed via Actuator:

Metric Type Description
auth.request.duration Timer Request duration by path, method, status
auth.jwt.created Counter JWT tokens created
auth.jwt.validation.success Counter Successful JWT validations
auth.jwt.validation.failure Counter Failed JWT validations (tagged by reason)
auth.api-key.authentication.success Counter Successful API key auth
auth.api-key.authentication.failure Counter Failed API key auth (tagged by reason)
auth.session.authentication.success Counter Successful session auth
auth.session.authentication.failure Counter Failed session auth (tagged by reason)

Health Checks

Endpoint Probes Description
GET /actuator/health - Overall health
GET /actuator/health/liveness Liveness Is the app alive?
GET /actuator/health/readiness Readiness Is the app ready for traffic?
GET /actuator/info - Application info

Database Overview

Entity Inventory

Entity Table Purpose
User users Authenticated user accounts
Role roles Named role definitions
Permission permissions Granular permission actions
- user_roles User-to-role assignment (join)
- role_permissions Role-to-permission grants (join)
ApiClient api_clients Registered API client apps
ApiKey api_keys Hashed API key credentials
RefreshToken refresh_tokens Hashed refresh token credentials
AuditLog audit_logs Append-only audit trail

Migrations

All schema changes are managed by Liquibase in src/main/resources/db/changelog/. The master changelog references 11 v1 migrations creating tables, indexes, constraints, and seed data.

Seed Data

Resource Username Password
Admin User admin dev-password
Dev User devuser dev-password

Seed data is for development only and should not be applied in production.

Postman Collection

A complete Postman Collection covering all endpoints is available at:

docs/postman/Auth Platform.postman_collection.json

Import it into Postman and set the baseUrl variable to your Auth Platform host. The collection includes:

  • Login, Validate, Refresh, Logout, Logout All
  • API Key creation, listing, and revocation
  • Actuator health, info, and metrics endpoints

Architecture Documentation

Detailed architecture decisions and design rationale are documented in docs/architecture/:

Document Topic
ADR 0001 Architecture decision records
ADR 0002 Pluggable provider architecture
ADR 0003 JWT token service
ADR 0004 Refresh token rotation
ADR 0005 API key management
ADR 0006 Session management
ADR 0007 Persistence model
ADR 0008 Authentication flow

Security

Path Access
GET /actuator/health/** Public
GET /actuator/info Public
/internal/** Gateway internal (no service-to-service auth yet)
/fallback/** Public
/actuator/** ADMIN role

CSRF is disabled globally (stateless service, no browser sessions at this level).

Contributing

See CONTRIBUTING.md for development setup, coding standards, and pull request process.

License

Licensed under the Apache License 2.0. See LICENSE.

About

Production-ready authentication and authorization platform built with Spring Boot 4, WebFlux, JWT, API Keys, Redis, PostgreSQL, and reactive microservices.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Sponsor this project

Packages

 
 
 

Contributors