Introduction
A common challenge when developing modern web applications is connecting an Angular frontend running on one origin to a Spring Boot backend running on another. Developers frequently encounter errors such as:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource.
Reason: CORS header 'Access-Control-Allow-Origin' missing.
Status code: 403
After attempting to enable CORS, additional issues often appear:
IllegalArgumentExceptionrelated toallowedOrigins- Deprecated Spring Security methods
- HTTP 403 Forbidden responses
- Authentication entry point errors
This guide explains the most common causes and solutions.
Understanding the CORS Problem
Suppose your Angular application is running on:
http://localhost:4200
and your Spring Boot backend is running on:
http://192.168.50.151:8080
When Angular attempts to call:
POST /login
the browser sends a CORS preflight request before the actual login request.
If the backend does not explicitly allow the frontend origin, the browser blocks the request.
Common Incorrect Configuration
Many developers initially try:
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
This causes the following exception:
IllegalArgumentException:
When allowCredentials is true,
allowedOrigins cannot contain "*"
Why This Happens
When credentials are enabled:
config.setAllowCredentials(true);
the server must return a specific origin:
Access-Control-Allow-Origin: http://localhost:4200
Returning:
Access-Control-Allow-Origin: *
is not permitted by the CORS specification.
Correct Solution Using allowedOriginPatterns
Instead of:
config.addAllowedOrigin("*");
use:
config.addAllowedOriginPattern("*");
Example:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedOriginPattern("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Spring Security 6 Configuration
Recent versions of Spring Security no longer use:
WebSecurityConfigurerAdapter
and many methods have been deprecated.
Instead, configure security using:
SecurityFilterChain
Example:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(withDefaults())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
Deprecated httpBasic() Method
Older configurations used:
http.httpBasic();
Modern Spring Security recommends:
http.httpBasic(withDefaults());
Example:
import static org.springframework.security.config.Customizer.withDefaults;
http.httpBasic(withDefaults());
Handling Preflight OPTIONS Requests
A very common reason for receiving:
403 Forbidden
is that Spring Security blocks the browser’s preflight request.
Browsers automatically send:
OPTIONS /login
before:
POST /login
You must allow these requests.
Example:
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
Why “Forbidden Entry Point” Happens
If Spring Security receives an unauthenticated request and does not know how to handle it, it may trigger an authentication entry point and return:
403 Forbidden
or
401 Unauthorized
Typical causes include:
- Missing
permitAll()on/login - Blocked OPTIONS requests
- Custom authentication filters intercepting login requests
- Incorrect filter ordering
Recommended Security Configuration
A simplified modern configuration:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(withDefaults())
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
CORS configuration:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Angular Client Example
Angular login request:
this.http.post(
'http://192.168.50.151:8080/login',
credentials,
{
withCredentials: true
}
);
If credentials such as cookies or sessions are used, the withCredentials flag must match the server’s CORS configuration.
Debugging Tips
When troubleshooting CORS and authentication issues:
Check Browser Developer Tools
Look for:
OPTIONS /login
and verify the response headers.
Verify Access-Control Headers
The response should contain:
Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Methods
Enable Spring Security Debug Logging
logging.level.org.springframework.security=DEBUG
This reveals which filter rejects the request.
Test With curl
Example:
curl -X OPTIONS \
http://192.168.50.151:8080/login \
-H "Origin: http://localhost:4200" \
-H "Access-Control-Request-Method: POST"
This helps determine whether the issue is CORS-related or authentication-related.
Conclusion
When integrating Angular with Spring Boot, CORS and security configuration issues are among the most common causes of failed login requests. Modern Spring Security requires updated configuration patterns using SecurityFilterChain, proper CORS handling with allowedOriginPatterns, and explicit permission for preflight OPTIONS requests.
By correctly configuring CORS, updating deprecated APIs, and allowing unauthenticated access to login endpoints, frontend applications can securely communicate with backend services without encountering browser-side CORS errors or Spring Security authorization failures.


