I am working on a project in react and spring boot, and I got issue with the cross origin from my spring server, I put the crossOrogin annotation on my controller and is not working me I tried many ways (from spring official web) non of them worked to me. Is anyone can help me please with that I really don’t know what to do. Here is my controller , ;
},
And this is my error with react:
error image for react uskg chrome
try this way:
#Configuration
public class CrossConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*") // SpringBoot2.4.0 [allowedOriginPatterns]replace[allowedOrigins]
.allowedMethods("*")
.maxAge(3600)
.allowCredentials(true);
}
}
I have a Spring Boot Rest application where I need to allow CORS requests.
Requests use the common path <host>:<port>/api/... and so far I only have two resources:
package my.controllers;
#RestController
#RequestMapping(path="/", produces="application/json")
public class DataController {
#GetMapping("/")
public ApiResponse<Map<String, Object>> getValues() {
// ...
}
#GetMapping("/sub")
public ApiResponse<String> getValuesSub() {
// ...
}
Here are two example requests from the Javascript client running at http://localhost:3000/:
fetch('http://localhost:2001/api/').then(/* ... */);
fetch('http://localhost:2001/api/sub')).then(/* ... */);
If I add the #CrossOrigin(origins = "*") annotation to the controller, CORS requests work fine; if I replace it implementing WebMvcConfigurer.addCorsMappings() though:
#ComponentScan(basePackages={ "my.controllers" })
#Configuration
public class WebappConfig implements WebMvcConfigurer {
// ...
#Override
public void addCorsMappings(CorsRegistry registry) {
LogManager.getLogger(getClass()).info("CORS settings");
registry.addMapping("/api/**").allowedOrigins("*").maxAge(3600);
}
CORS requests fail, and I get (in Firefox, Chrome shows a similar error message):
CORS header 'Access-Control-Allow-Origin' missing
I see the log entry, so the method is surely invoked.
I've seen other questions mentioning Spring Security or Spring Data (I use none), so here's my dependencies list in case I'm missing something:
spring-boot-starter-web
spring-boot-starter-tomcat
spring-boot-starter-log4j2
spring-boot-configuration-processor
commons-lang3
commons-beanutils
What's the right way to set CORS settings to the whole application, without using the #CrossOrigin annotation on each controller?
UPDATE
I'm initializing a Rest servlet like this:
#Bean
public ServletRegistrationBean<DispatcherServlet> registerDispatcherServlet(DispatcherServlet servlet) {
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(servlet);
servlet.setContextConfigLocation("");
registration.addUrlMappings("/api/*");
registration.setLoadOnStartup(1);
return registration;
}
The logs says:
Servlet dispatcherServlet mapped to [/api/*]
Servlet dispatcherServlet mapped to [/]
Servlet dispatcherServlet was not registered (possibly already registered?)
Could it be that the given Cors settings are going to the mentioned unregistered servlet?
I got it working by replacing "/api/**" with "/**" in the call to addMapping() when configuring the CORS registry:
#Override
public void addCorsMappings(CorsRegistry registry) {
LogManager.getLogger(getClass()).info("CORS things!");
registry.addMapping("/**").allowedOrigins("*").maxAge(3600);
}
Though I'm puzzled about why this is the setting that makes it work, and what would I have to do if I need to expose several independent Rest paths, i.e.:
http:/host:port/public-api (from all over the Internet)
http:/host:port/reserved-api (from well known hosts)
http:/host:port/admin-api (same host only)
I am using Angular6 as FrontEnd running on http:// localhost:4200 and Spring Boot (which has in built Tomcat server) as backend (exposing a GET Rest API) running on https:// localhost:8083/ldap . When I run this, I am getting CORS policy error on the browser. So I searched on internet and tried multiple fixes which were suggested on internet. I am not sure what I am missing on each of the solution below.
Unsuccessful Fix 1: I tried to run it via proxy.
-> Created a proxy.config.json in parallel to package.json with below
content.
{
"/ldap/": {
"target": "https://localhost:8083",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
-> Added below entry in package.json inside script block there.
"start":"ng serve --proxy-config proxy.config.json",
-> In the service class, tried calling my spring boot backend rest API
like below.
return this.http.get('/ldap');
Now when I run my app, I got below error:
GET http:// localhost:4200/ldap 404 (Not Found) : zone.js:3243
Unsuccessful Fix 2: I added below headers before calling the Rest API in my frontend.
getUserAuthenticatedFromLDAP() {
const httpOptions = {
headers: new HttpHeaders({
'crossDomain': 'true',
'mode' : 'cors',
'allowCredentials': 'true',
'origins': '',
'allowedHeaders': '',
'Access-Control-Allow-Origin': '',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
'Access-Control-Max-Age': '86400'
})
};
return this.http.get('https://localhost:8083' , httpOptions);
}
Access to XMLHttpRequest at 'https://localhost:8083/' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Unsuccessful Fix 3: Rather than making changes at front end, I tried to make changes at API level by adding below code at controller level.
#Controller
#CrossOrigin(origins = "http://localhost:4200")
public class WelcomeController {
// This is for LDAP Authentication
#GetMapping("/ldap")
#ResponseBody
public Authentication hello() {
return LdapSecurity.getAuthentication();
}
}
Here I am getting below error again:
Access to XMLHttpRequest at 'https://localhost:8083/' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
More unsuccessful fixes:
I even tried to change headers of Tomcat using application.properties file but could not find sufficient example or piece of code to make any change.
On internet, some people suggested to implement filter on API level but I am not sure that in whcih class I need to add those overriden filter method. I am stuck in this issue for last 2 days.
PS: I see some people have implemented CORS filter at API layer or implemented class like below. Now my question is if I implement below class then where do I need to refer this class ? Is it web.xml or any other place.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
I was using Spring security feature for LDAP authentication. But now I removed Spring security feature for LDAP and used a basic program in java to make a connection with LDAP. After that I used CrossOrigin tag in controller layer and now I am not getting CORS issue. Thanks you all for your help.
please have a look here, you need to enable cors in your method/controller
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
I'm trying to enable the cross origin header to be able to reach the service from anywhere (only on local env) but I cannot.
#Configuration
#RequiredArgsConstructor
public class CrossOriginConfig implements WebMvcConfigurer {
private final SecurityConfiguration securityConfiguration;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("*").allowedOrigins(securityConfiguration.getCrossOrginFilter());
}
}
I made a custom index.html with an ajax call and it fails due to the Allow-Cross-Origin header missing and it comes from another origin.
Simple Spring Boot 2.0 controllers are used with #RestController annotation and simple #GetMapping.
What I missed? What should I include and where?
You need to add the below annotation on either on the controller class or the specific method:
#CrossOrigin
By default, its allows all origins, all headers, the HTTP methods specified in the #RequestMapping annotation and a maxAge of 30 minutes is used.
If you want to allow only http://localhost:8080 to send cross-origin requests
#CrossOrigin(origins = "http://localhost:8080")
Replace the host and port accordingly.
Check the below Spring documentation for more information:
https://spring.io/guides/gs/rest-service-cors/
As Georg Wittberger pointed out the problem was with the mapping. I used the * wildcard what is not good for paths.
Instead of this: registry.addMapping("*")
I used this: registry.addMapping("/**") and it's working fine.
I am using keycloak to secure my rest service. I am refering to the tutorial given here. I created the rest and front end. Now when I add keycloak on the backend I get CORS error when my front end makes api call.
Application.java file in spring boot looks like
#SpringBootApplication
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
#Bean
public WebMvcConfigurer corsConfiguration() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*")
.allowedMethods(HttpMethod.GET.toString(), HttpMethod.POST.toString(),
HttpMethod.PUT.toString(), HttpMethod.DELETE.toString(), HttpMethod.OPTIONS.toString())
.allowedOrigins("*");
}
};
}
}
The keycloak properties in the application.properties file look like
keycloak.realm = demo
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = tutorial-backend
keycloak.bearer-only = true
keycloak.credentials.secret = 123123-1231231-123123-1231
keycloak.cors = true
keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = user
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*
The sample REST API that I am calling
#RestController
public class SampleController {
#RequestMapping(value ="/api/getSample",method=RequestMethod.GET)
public string home() {
return new string("demo");
}
}
the front end keycloak.json properties include
{
"realm": "demo",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "tutorial-frontend",
"public-client": true
}
The CORS error that I get
XMLHttpRequest cannot load http://localhost:8090/api/getSample. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 401.
I know.. the Problem is quite Old.
But if you've Problems with the local development with Spring Boot + Keycloak you can use the Config
keycloak.cors=true
in your application.properties.
Cheers :)
Try creating your CORS bean like my example. I recently went through the same thing (getting CORS to work) and it was a nightmare because the SpringBoot CORS support is currently not as robust or straightforward as the MVC CORS.
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
This is how I set it up to accept any origin application-wide, but if you change a few of the parameters you should be able to replicate what you want. ie. if you wanted to add only the methods you mentioned, chain some addAllowedMethod(). Allowed origins would be the same, and then your addMapping("/api/*") would become source.registerCorsConfiguration("/api/*", config);.
Edit:
Spring Data Rest and Cors
Take a look at this. Sebastian is on the Spring engineering team so this is about as good as you're going to get for an official answer.
I came here with the same problem and fix it ommiting authentication for OPTIONS method only, like this:
keycloak.securityConstraints[0].security-collections[0].omitted-methods[0]=OPTIONS
It worked for me because the OPTIONS request Keycloack does, does not include Authentication header.
UPDATE
There was something with my browser's cache so I could not see the real impact of a change in my backend code. It looks like what really worked for me was enabling all CORS origins at #RestController level, like this:
#CrossOrigin(origins = "*")
#RestController
public class UsersApi {...}
I don't have access to code examples, but based on the code configurations you have included, it looks like a missing configuration is causing spring to exclude CORS headers.
J. West's response is similar to recent issues I encountered with Spring and CORS, I would however caution you to look into which implementation a spring example references, because there are two. Spring Security and Spring MVC Annotations. Both of these implementations work independent of each other, and can not be combined.
When using the filter based approach as you are (even boiled down), the key was to set allow credentials to true, in order for the authentication headers to be sent by the browser across domains. I would also advise using the full code method proposed above, as this will allow you to create a far more configurable web application for deployment across multiple domains or environments by property injection or a service registry.
Access-Control-Allow-Origin header is supposed to be set by the server application basis the Origin request header provided in the request to the server application. Usually browsers set the Origin header in request whenever they sense a cross origin request being made. And they expect a Access-Control-Allow-Origin header in response to allow it.
Now, for keycloak, I struggled with the same issue. Looking at this, it seems like keycloak does not add Access-Control-Allow-Origin header in case of error response. However, for me it was not adding this header in the response even in case of success response.
Looking into the code and adding breakpoints, I noticed that the webOrigin for client object was not getting populated from the Origin header even if passed and hence CORS was not adding the access control response header.
I was able to get it working by adding the following line of code just before the CORS build call:
client.addWebOrigin(headers.getRequestHeader("Origin").get(0));
before:
Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
Once I built the code with this change and started the server, I started getting the three access control response headers:
Access-Control-Expose-Headers: Access-Control-Allow-Methods
Access-Control-Allow-Origin: http://localhost:9000
Access-Control-Allow-Credentials: true
I am using client credentials grant type; hence i added it only in the buildClientCredentialsGrant at TokenEndpoint.java#L473.
I still need to do some more code diving in order to say for sure that it is a bug for success responses at well and to find a better place to set this on the client object in keycloak code (like where client object is being constructed)
You are welcome to give it a try.
UPDATE:
I take this back. I re-registered my client in keycloak with Root URL as http://localhost:9000 (which is my front-end's application port) and i started getting the proper access control response headers. Hope this helps you.
I know the problem is too old but, I found better solution.
Read more at official documentation
Inside your application.yml file
keycloak:
auth-server-url: http://localhost:8180/auth
realm: CollageERP
resource: collage-erp-web
public-client: true
use-resource-role-mappings: true
cors: true
cors-max-age: 0
principal-attribute: preferred_username
cors-allowed-methods: POST, PUT, DELETE, GET
cors-allowed-headers: X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers
or you can config using application.properties file
keycloak.auth-server-url= http://localhost:8180/auth
keycloak.realm= CollageERP
keycloak.resource= collage-erp-web
keycloak.public-client= true
keycloak.use-resource-role-mappings= true
keycloak.cors= true
keycloak.cors-max-age= 0
keycloak.principal-attribute= preferred_username
keycloak.cors-allowed-methods= POST, PUT, DELETE, GET
keycloak.cors-allowed-headers= X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers
and my java adaper class
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import javax.ws.rs.HttpMethod;
#KeycloakConfiguration
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.cors().and().authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/api/**")
.authenticated()
.anyRequest().permitAll();
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
I want to share with you the solution that worked for me hoping to help whoever is facing the same issue. I am going to give you two solutions actually.
Spring reactive:
#Configuration
#EnableWebFluxSecurity
public class SecurityConfig {
#Autowired
private ReactiveClientRegistrationRepository clientRegistrationRepository;
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
CorsConfiguration cors_config = new CorsConfiguration();
cors_config.setAllowCredentials(true);
cors_config.applyPermitDefaultValues();
cors_config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "null"));
cors_config.setAllowedMethods(List.of("GET","POST","OPTIONS","DELETE"));
cors_config.setAllowedHeaders(List.of("*"));
http.cors().configurationSource(source -> cors_config)
.and()
.csrf().disable()
.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
.oauth2Login()//Setting Oauth2Login
.authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("")).and()
.logout(logout -> logout //Setting Oauth2Logout
.logoutHandler(logoutHandler())
.logoutSuccessHandler(oidcLogoutSuccessHandler()));
return http.build();
}
private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {
OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
new OidcClientInitiatedServerLogoutSuccessHandler(this.clientRegistrationRepository);
// Sets the location that the End-User's User Agent will be redirected to
// after the logout has been performed at the Provider
oidcLogoutSuccessHandler.setPostLogoutRedirectUri("");
return oidcLogoutSuccessHandler;
}
private DelegatingServerLogoutHandler logoutHandler() {
//Invalidate session on logout
return new DelegatingServerLogoutHandler(
new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler());
}
}
Spring MVC:
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
CorsConfiguration cors_config = new CorsConfiguration();
cors_config.setAllowCredentials(true);
cors_config.applyPermitDefaultValues();
cors_config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "null"));
cors_config.setAllowedMethods(List.of("GET","POST","OPTIONS","DELETE"));
cors_config.setAllowedHeaders(List.of("*"));
http.cors().configurationSource(source -> cors_config).and()...
return http.build();
}
}
Be sure to have cors enabled on Keycloak too, navigate to
realm->clients->settings->weborigins
and submit your permitted origins.
If you are sending credentials or cookies in your requests, be sure to configure it, for example, if you are using ReactJS:
const httpConfig = { withCredentials: true };
axios.get('YourUrl', httpConfig)
.then(response => {})
.catch(error => {})
.finally(() => {});
When your client is sending an Authentication header, you cannot use
allowedOrigins("*"). You must configure a specific origin URL.
Since you have set the property keycloak.cors = true in your application.properties file, you have to mention the CORS enabled origins in the Keycloak server. To do that follow the below steps.
Go to Clients -> Select the client (Token owner) -> Settings -> Web Origins
Add origins one by one or add * to allow all.
After doing this you have to get a new token. (If you decode the token you will see your origins as allowed-origins": ["*"])
Setting the property keycloak.cors = false is another option. But this completely disables CORS.