Skip to content

Authentication & Security Module

The SREDSimplify backend employs a stateless, token-based authentication architecture utilizing JWT (JSON Web Tokens) and Spring Security.

1. Core Authentication Flows

The system supports multiple authentication vectors:

  • Email & Password: Standard registration with BCrypt password hashing.
  • Google OAuth 2.0: Secure third-party login via ID Token validation.
  • Invitation Codes: Optional gating for enterprise onboarding.

Sequence Diagram: Registration & Login

mermaid
sequenceDiagram
    participant Client
    participant AuthController
    participant AuthServiceImpl
    participant PostgreSQL
    participant Redis
    participant EmailQueue

    %% Registration Flow
    Note over Client,EmailQueue: Flow 1: Account Registration
    Client->>AuthController: POST /api/v1/auth/register
    AuthController->>AuthServiceImpl: register(email, password)
    AuthServiceImpl->>PostgreSQL: Verify email uniqueness
    AuthServiceImpl->>PostgreSQL: Save User & UserIdentity (BCrypt)
    AuthServiceImpl->>Redis: SET verification_token (24h TTL)
    AuthServiceImpl->>EmailQueue: XADD sred:email:send (Welcome + Verify Link)
    AuthServiceImpl-->>Client: 201 Created (Proceeds to Auto-login)

    %% Login Flow
    Note over Client,PostgreSQL: Flow 2: Email Login
    Client->>AuthController: POST /api/v1/auth/login
    AuthController->>AuthServiceImpl: login(email, password)
    AuthServiceImpl->>PostgreSQL: Authenticate (Verify BCrypt hash)
    AuthServiceImpl->>AuthServiceImpl: Generate Access Token (15m)
    AuthServiceImpl->>AuthServiceImpl: Generate Refresh Token (7d)
    AuthServiceImpl-->>Client: 200 OK {accessToken, refreshToken}

2. Spring Security Filter Chain

Security is enforced via the JwtAuthenticationFilter, which runs on every incoming request.

Token Extraction

The filter inspects the standard Authorization header:

java
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
    // Valid Bearer Token found
}

Context Population

If the token's signature is valid and it hasn't expired, the filter:

  1. Extracts the userId.
  2. Loads user authorities (Roles: USER, ADMIN).
  3. Populates the SecurityContextHolder, allowing downstream Controllers to use @AuthenticationPrincipal.

3. Secure Token Revocation (Logout)

Because JWTs are stateless, they cannot be conventionally "invalidated" before expiration. We handle secure logouts using a hybrid approach:

  • The Refresh Token is deleted from the client and invalidated in Redis.
  • The Access Token (which has a short lifespan of 15 minutes) is discarded by the frontend.
  • For critical security events (e.g., password change), the jwt_secret or a user-specific token version is rotated in the database.