Spring Security - permitAll() returning 403 Forbidden
I'm configuring Spring Security in my Spring Boot application, but even though I'm using permitAll()
on certain endpoints, I'm still getting 403 Forbidden responses. Here's my security configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/health", "/actuator/health").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
}
And my application.yml
:
server:
servlet:
context-path: /api
But when I try to access /api/public/test
, I still get 403 Forbidden. What am I doing wrong?
Solution
The issue is caused by a context-path configuration conflict. When you set server.servlet.context-path=/api
in your properties, Spring Boot prepends /api
to all your endpoints, but your security configuration is still looking for the original paths.
For example:
- Without context-path: Your endpoint
/api/public/test
is accessible athttp://localhost:8080/api/public/test
- With context-path=/api: Your endpoint
/api/public/test
becomes accessible athttp://localhost:8080/api/api/public/test
To fix this, you need to remove context-path from your application.yml:
server:
servlet:
# context-path: /api # Remove or comment this out
Debugging
If you're still having issues, enable debug logging to see the actual request paths:
logging:
level:
org.springframework.security: DEBUG
org.springframework.web: DEBUG
Alternative #1
I've encountered this exact issue. The problem is that the context-path is prepended to every request path, so the security configuration is not able to match against it.
If you want to keep using server.servlet.context-path
, you will have to update the paths in the code
Replace the /api/public
path with /public
in the security configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll() // This matches /api/public/** when context-path is /api
.requestMatchers("/health", "/actuator/health").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
}
You will also need to update your controller, replacing /api/public/test
with /public/test
.
You can test by calling the endpoint http://localhost:8080/api/public/test
as /api
is prepended automatically.