CustomAuthenticationEntryPoint.java

package com.stocks.stockease.security;

import java.io.IOException;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Custom entry point for handling authentication failures (401 Unauthorized).
 * 
 * Implements Spring Security's AuthenticationEntryPoint contract to provide
 * REST-compliant error responses for unauthenticated requests on protected endpoints.
 * 
 * Invoked when:
 * - Request missing Authorization header (no JWT token)
 * - Authorization header present but token invalid/expired
 * - JwtFilter throws authentication exception
 * 
 * Response format:
 * - HTTP 401 Unauthorized status
 * - Content-Type: application/json
 * - Body: {"error": "Invalid username or password"}
 * 
 * Design rationale:
 * - JSON response prevents browser default 401 page (REST-compliant)
 * - Generic error message prevents username enumeration attacks
 * - Single implementation serves all unauthenticated requests
 * 
 * @author Team StockEase
 * @version 1.0
 * @since 2025-01-01
 */
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    /**
     * Handles unauthenticated request by returning 401 JSON error response.
     * 
     * Called by Spring Security's ExceptionTranslationFilter when
     * AuthenticationException is thrown (e.g., invalid/missing JWT).
     * 
     * Response: {"error": "Invalid username or password"}
     * 
     * Security considerations:
     * - Returns generic error message (doesn't reveal if username exists)
     * - Status 401 standard HTTP code for authentication failures
     * - JSON format allows frontend to parse and handle gracefully
     * - Prevents browser from showing default 401 page
     * 
     * @param request HttpServletRequest that triggered authentication failure
     * @param response HttpServletResponse for writing error
     * @param authException exception that triggered this entry point
     * @throws IOException if response writing fails
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException {
        // Set HTTP status 401 Unauthorized
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // Set content type to JSON for REST compliance
        response.setContentType("application/json");
        // Write generic error message (prevents username enumeration attacks)
        response.getWriter().write("{\"error\": \"Invalid username or password\"}");
    }
}