Skip to content

Improve documentation for configuring Spring Security with '/error' #45663

Open
@UsamaButt1593

Description

@UsamaButt1593

When using Spring Boot with Spring Security, if an unauthenticated user sends a request to a public endpoint e.g. /auth/signup that results in an exception (e.g., validation error), Spring framework intercepts the error and redirects it to the /error endpoint.

By default, Spring Boot configures /error for exception resolution. However, Spring Security also protects /error, requiring authentication by default.

As a result, expected application exceptions (like MethodArgumentNotValidException) are never properly returned to the client for unauthenticated users. Instead, the user receives a 403 Forbidden or 401 Unauthorized error, and the original exception details are lost.

This breaks consistent error handling for APIs that are supposed to be public (e.g., /auth/signup).

Environment

  • Spring Boot version: 3.2.x
  • Spring Security version: 6.x
  • Java: 17+
  • Application Type: REST API using stateless authentication (JWT)

Code to reproduce

// Controller
@RestController
@RequestMapping("/auth")
public class AuthController {
    
    @Autowired
    private AuthService authService;

    @PostMapping("/signup")
    public ResponseEntity<?> signUp(@Valid @RequestBody SignUpRequestDTO signUpRequestDTO) {
        return ResponseEntity.ok(
            userService.createUser(signUpRequestDTO.getEmail(), signUpRequestDTO.getPassword())
         );
    }


// DTO
@Data
public class CreateUserRequestDTO {
    @Email
    private String email;

    @NotBlank
    private String password;
}

// Config
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
                return http.csrf(csrf -> csrf.disable())
                                .authorizeHttpRequests(auth -> auth
                                    .requestMatchers("/auth/**").permitAll()
                                    .anyRequest().authenticated())
                                .build();
        }

}

}

if we send a http request with invalid body like:

POST http://localhost:8080/auth/signup
Content-Type: application/json

{
  "email": "NOT_A_VALID_EMAIL",
  "password": "password"
}

expected response should be 400 Bad Request with error details while actual response we get is 401 Unauthorized.

HTTP/1.1 401 
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Content-Length: 121
Connection: close

{
  "path": "/error",
  "error": "Unauthorized",
  "message": "Full authentication is required to access this resource",
  "status": 401
}

Expected Behavior

The /error endpoint should either:

  • Be permitted by default in Spring Security to allow unauthenticated users to receive meaningful error responses, or
  • The documentation should clearly recommend developers permit the /error endpoint in security configuration when using stateless APIs.

Additional Context

This behavior is confusing and non-obvious to developers building public or semi-public REST APIs. Better defaults or clearer documentation would significantly improve the developer experience.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions