Skip to content

Phase 5 - Authentication & API Security

Backend Security Audit - Sprint 1

A full security audit of the backend code was performed on 04/05/2026. The following findings were identified and fixed.

Findings & Status

# File Issue Severity Status
1 ProjectController.java GET /projects had no @PreAuthorize - any authenticated user could list all projects (IDOR) Critical Fixed
2 ReagentController.java GET /reagents and GET /reagents/{id} had no @PreAuthorize Critical Fixed
3 SecurityConfig.java Swagger UI exposed without auth in production High Fixed
4 application-prod.yaml JWT issuer-uri using HTTP and localhost in production config Critical Fixed
5 SecurityConfig.java No CORS configuration defined Medium Fixed
6 application.yaml Actuator prometheus endpoint exposed without role restriction Medium Fixed

Fixes Applied

Authorization on read endpoints:

// GET /projects - restricted to authenticated users
@PreAuthorize("@authz.isUser(authentication)")
public List<ProjectResponse> findAll() { ... }

// GET /reagents - restricted to authenticated users
@PreAuthorize("@authz.isUser(authentication)")
public List<ReagentResponse> findAll() { ... }

CORS configuration with allowlist:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(allowedOrigins); // injected from env
    config.setAllowedMethods(List.of("GET", "POST", "PATCH", "DELETE", "OPTIONS"));
    config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
    config.setAllowCredentials(true);
    ...
}

Swagger disabled in production:

springdoc:
  swagger-ui:
    enabled: false
  api-docs:
    enabled: false

Actuator restricted to ADMIN:

.requestMatchers("/actuator/**").hasRole(AppRole.ADMIN.name())

JWT issuer-uri via environment variable:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: ${KC_ISSUER_URI}


Authentication Architecture

AliQuest uses a double RBAC approach:

  1. Keycloak SSO - Core organisation-level authentication and authorisation via JWT
  2. Internal Authorization Service - Project-level RBAC (VIEWER, RESEARCHER, MAINTAINER roles)

Hardware vending machines authenticate as Keycloak clients via client ID and secret, bound to azp claim in the JWT.


Frontend Auth Guards

The frontend uses ProtectedRoute components to block unauthorised access:

  • Researchers are blocked from: /users, /settings, /reagent/edit, /reagent/add, /project/edit, /project/add
  • Security logging on every blocked attempt
  • Unauthorized page shown when access is denied
  • Mock auth in auth.ts - ready to wire to KC JWT

Pending

  • Wire frontend auth.ts to real Keycloak JWT once KC config is finalised
  • Input validation with zod on all frontend forms
  • IDOR fix on user listing endpoint in backend (flagged by Jabbar, to be fixed)
  • Rate limiting on auth endpoints - to be implemented at Traefik level