Description
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.