Skip to content

Forwarding JWT Token

Paulo Gomes da Cruz Junior edited this page Nov 19, 2025 · 1 revision

Legacy Security Integration via JWT Forwarding

📌 Overview

This feature introduces secure JWT token propagation from the main backend application to the legacy API. It ensures that the authenticated user's identity and roles are preserved across service boundaries, enabling consistent authorization and auditing throughout the system.

⚙️ How It Works

  • JWT Injection into Outbound Requests
    A new Spring component, JwtForwarderRequestInitializer, is responsible for injecting the current user's JWT into the Authorization header of outbound HTTP requests targeting the legacy API.

  • RestClient Configuration
    The legacy API's RestClient bean is configured to use the JwtForwarderRequestInitializer, ensuring all requests carry the bearer token.

  • User Context Extraction
    A helper class, LoggedUserHelper, safely extracts the JWT from Spring Security's SecurityContextHolder, making it reusable across components.

  • Legacy API Security Enablement
    The legacy service is now configured as a Spring Security resource server, capable of validating JWTs and enforcing access control based on token claims.

  • Testing Enhancements
    Integration tests now use @WithMockJwt to simulate authenticated requests and validate token propagation and access control logic.

🧠 Why It Works

  • Spring Security Compatibility
    By leveraging Spring Security's built-in support for JWT-based authentication, the system ensures robust and standardized security practices.

  • Token Consistency
    Forwarding the same JWT across services maintains a unified authentication context, eliminating discrepancies between systems.

  • Minimal Intrusion
    The implementation avoids custom session bridging or proprietary headers, relying instead on standard HTTP authorization mechanisms.

✅ Benefits

  • Cross-Service Authorization
    The legacy API can now enforce role-based access control using the same JWT issued by the identity provider, allowing for fine-grained filtering based on user roles or identity.

  • Improved Auditability
    Actions performed in the legacy system can be reliably traced back to the authenticated user, enhancing accountability and compliance.

  • Simplified Architecture
    Removes the need for custom headers or session replication logic, reducing complexity and potential security pitfalls.

  • Future-Proofing
    Aligns the legacy system with modern authentication standards, paving the way for smoother integration with other services or identity providers.

Absolutely! Here's a Mermaid sequence diagram that illustrates how JWT forwarding works between the main backend and the legacy API, based on your PR implementation:

Got it, Paulo! Based on the actual implementation from the PR’s “Files changed” tab, here’s the real code that forwards the JWT from the backend to the legacy service:

🧩 JWT Forwarding Implementation

✅ 1. LoggedUserHelper.java

This helper extracts the JWT from the current security context:

public String getToken() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication == null || !authentication.isAuthenticated()) {
        return null;
    }

    if (authentication instanceof JwtAuthenticationToken jwtAuth) {
        return jwtAuth.getToken().getTokenValue();
    }

    return null;
}

✅ 2. JwtForwarderRequestInitializer.java

This Spring component injects the JWT into outbound HTTP requests:

@Component
@RequiredArgsConstructor
public class JwtForwarderRequestInitializer implements ClientHttpRequestInitializer {

    private final LoggedUserHelper userHelper;

    @Override
    public void initialize(ClientHttpRequest request) {
        request.getHeaders()
               .add(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", userHelper.getToken()));
    }
}

✅ 3. GlobalConfiguration.java

The legacy API client is configured to use the JWT forwarder:

@Bean
public RestClient legacyApi(
    HrsConfiguration configuration,
    JwtForwarderRequestInitializer jwtForwarder
) {
    return RestClient
        .builder()
        .baseUrl(configuration.getLegacyApi().getAddress())
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .requestInitializer(jwtForwarder)
        .build();
}

Mermaid Diagram: JWT Forwarding Flow

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant LegacyAPI

    User->>Frontend: Login & receive JWT
    Frontend->>Backend: Request with JWT
    Backend->>LoggedUserHelper: Extract JWT from SecurityContext
    Backend->>JwtForwarderRequestInitializer: Add JWT to Authorization header
    Backend->>LegacyAPI: Request with forwarded JWT
    LegacyAPI->>Spring Security: Validate JWT
    LegacyAPI->>LegacyAPI: Apply role-based filtering
    LegacyAPI-->>Backend: Response
    Backend-->>Frontend: Response
    Frontend-->>User: Display filtered data
Loading

Clone this wiki locally