Improve documentation for configuring Spring Security with '/error'
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.
The documentation should clearly recommend developers permit the /error endpoint in security configuration when using stateless APIs.
It is documented https://docs.spring.io/spring-security/reference/servlet/getting-started.html#servlet-hello-auto-configuration in Spring Security, and Spring Boot documentation refers to Spring Security documentation in the first paragraph.
Be permitted by default in Spring Security to allow unauthenticated users to receive meaningful error responses
By default, everything in the application is protected, and it is up to the user to determine which URLs should be allowed. For the ErrorController, the path specified in the @RequestMapping annotation can be overridden in the application by setting the server.error.path or error.path properties. Alternatively, a custom ErrorController bean can be defined with a path other than /error and registered with ErrorPageRegistrar.
In general, users typically register their own SecurityFilterChain, and allowing the /error path by adding a single line in the configuration is pretty straightforward.
If Spring Security is on the classpath, then web applications are secured by default.
I think this sentence can be rephrased a little bit with including information that Boot's /error endpoint is also secured by default.
What sentence is that exactly, @nosan?
I think the first one that mentions that applications are secured by default.
Maybe it could be rephrased to something like:
If Spring Security is present on the classpath, web applications are secured by default. This includes securing Spring Boot's
/errorendpoint.
Or maybe add a WARN/NOTE section that mentions this.