Access-Control-Allow-Origin Problem in ReactJS - reactjs

I have an issue when I try to access the backend.
Questions:
Do have any configure CORS in ReactJs?(in axios create or ..)
Are there any best way to do the CORS configuration in Spring Boot and ReactJs?
configurations are following below what I done,
Access to XMLHttpRequest at 'http://localhost:8282/opsprime/api/products?title_contains=a' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
So, I configured the backend(spring boot) as,
#RestController
#CrossOrigin(origins = "*", allowedHeaders = "*")
public class TestController {
....
}
and this is the reactJs configuration,
export default axios.create({
baseURL: 'http://localhost:8282/opsprime/api',
timeout: 1000,
headers: {
'Authorization' : `Bearer 4b21949a-4829-43cc-asex-1d0512478676`
}
});

Add this code to your spring boot application configuration, you can change the value of CORS_ORIGIN_ALLOW to identify on which methods CROSS can be implemented.
#Configuration
public class CorsSecurity implements WebMvcConfigurer {
private final String[] CORS_ORIGIN_ALLOW = {"/**"};
#Override
public void addCorsMappings(CorsRegistry registry) {
for (String cors : CORS_ORIGIN_ALLOW)
registry.addMapping(cors).allowedOrigins("*").allowedHeaders("*").allowedMethods("*");
}
}

Related

React JS send post request to Springboot Rest Server and get error

I am hosting my React app in localhost:3000, and hosting my SpringBoot RESTServer at localhost:8080, tried to send a post request to that server and got following error:
Access to XMLHttpRequest at 'http://localhost:8080/employees' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
but i already put Access-Control-Allow-Origin in my code:
axios.post('http://localhost:8080/employees', params, {
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'mode': 'no-cors'
}
}
)
API tested with postman and it worked.
Please help me.
That is caused by the CORS issue. You can google it and acquire lots of explanation which will tell you why the request is blocked when you call an api through the browser.
Basically, the CORS issue of Access-Control-Allow-Origin could be solved by setting you api endpoint. For sprint-boot api, you can try this two way.
Add #CrossOrigin onto the specific path controller
#CrossOrigin(origins = "http://localhost:3000")
#GetMapping("/employees")
public Employees getEmployees() {
// ...
}
Set the global CORS configuration
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
// Allow all origin to call your api
registry.addMapping("/**");
}
};
}
}
You can reference this article for more clearly CORS settings in spring-boot.

Spring Boot / React blocks CORS

I've got an api configured with Spring Boot on my localhost.
My Spring Boot controller should allow CORS requests, as I'm working with #CrossOrigin:
#RestController
#CrossOrigin
#RequestMapping("/api")
public class imageController {
#GetMapping("/images")
public List<Image> findAll(){
return imageService.findAll();
}
}
When testing with Postman / cURL everything is working fine (but cURL doesn't care about CORS policies...).
Now I'm trying to access the ressource 'http://localhost:8081/api/images' from my React application with axios.
I get following response-header, which determines that the request was blocked because of CORS (see 'X-XSS-Protection').
Cache-Control
no-cache, no-store, max-age=0, must-revalidate
Connection
keep-alive
Date
Tue, 23 Mar 2021 11:10:54 GMT
Expires
0
Keep-Alive
timeout=60
Pragma
no-cache
Set-Cookie
JSESSIONID=0683F0AD7647F9F148C9C2D4CED8AFE6; Path=/; HttpOnly
Transfer-Encoding
chunked
Vary
Origin
Vary
Access-Control-Request-Method
Vary
Access-Control-Request-Headers
WWW-Authenticate
Bearer realm="Unknown"
X-Content-Type-Options
nosniff
X-Frame-Options
DENY
X-XSS-Protection
1; mode=block
My axios request looks like this:
function findAll() {
return instance.get('/api/images')
}
const instance = axios.create({
baseURL: `${config.API_BASE_URL}`,
headers: {
'Content-Type': 'application/json'
}
})
instance.interceptors.request.use(request => {
console.log('Starting Request', JSON.stringify(request, null, 2))
return request
})
instance.interceptors.response.use(response => {
console.log('Response:', JSON.stringify(response, null, 2))
return response
})
...and it's called by following code:
componentDidMount() {
this.setState({ isLoading: true })
ImageService.authToken(keycloak.token)
ImageService.findAll().then((res) => {
this.setState({ images: res.data, isLoading: false });
});
}
How do I configure Spring Boot to allow such requests and not blocking my request by CORS policies?
Note, that my application is secured by keycloak. But I dont think the configuration of keycloak is relevant for this case. Please let me know if you need the Spring Boot configuration of keycloak.
Hi you need to create a global cors configuration in your spring boot project.Create a class and annotate it with #Configuration. You can follow this example below.
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
};
}
}
Here is the full guide that spring framework provides
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
Do you maybe have a Spring security configuration (#EnableWebSecurity / #EnableSpringSecurity) in place that may be interfering ? If so, you could configure cors() there as well.
#Configuration
#EnableWebSecurity
#EnableSpringSecurity
class WebSecurityConfiguration(...)
override fun configure(http: HttpSecurity) {
http.cors().configurationSource {
CorsConfiguration().apply {
allowedOrigins = listOf("*")
allowedMethods = listOf("GET", "OPTIONS")
allowedHeaders = listOf("*")
}
}
Also see https://docs.spring.io/spring-security/site/docs/4.2.19.BUILD-SNAPSHOT/reference/html/cors.html

Enable CORS in springboot mail API

I have easy mail sending springboot API and reactjs app for fetch.
Hosted in nginx server.
React app running well localhost, email working everything okei but if I run on a server it gives an error.
I have tried to add different Nginx server settings and add Springboot
#CrossOrigin(origins = "http://xx.xxx.xxx.xxx/") but have not found any help so far.
Where do I have to allow CORS if I deploy to server?
Nginx server default:
server {
listen 80 default_server;
root /var/www/name/build;
server_name xx.xxx.xxx.xxx;
index index.html index.htm;
location / {
}
}
Springboot:
#PostMapping
public void sendFeedback(#RequestBody Feedback feedback,
BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ValidationException("Feedback is not valid");
}
// Create a mail sender
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Properties props = mailSender.getJavaMailProperties();
mailSender.setHost(this.emailCfg.getHost());
mailSender.setPort(this.emailCfg.getPort());
mailSender.setUsername(this.emailCfg.getUsername());
mailSender.setPassword(this.emailCfg.getPassword());
// Create an email instance
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(feedback.getEmail());
mailMessage.setTo("test#gmail.com");
mailMessage.setSubject("Testing mail");
mailMessage.setText(feedback.getFeedback());
mailSender.send(mailMessage);
}
Reactjs code I have:
fetch(url,{
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(state)
}).then(response =>{
console.log(data)
}).catch(error =>{
console.log(error)
})
Output:
Access to fetch at 'http://xx.xxx.xxx.xxx:8080/feedback-0.0.1-SNAPSHOT' from
origin 'http://xx.xxx.xxx.xxx' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.
Add a CORS config as below :
CORSConfig.java
#Configuration
public class CORSConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD");
}
}
OR
Annonate your controller
#CrossOrigin
#PostMapping
public void sendFeedback(#RequestBody Feedback feedback,
BindingResult bindingResult){
if(bindingResult.hasErrors()){
throw new ValidationException("Feedback is not valid");
}
// Create a mail sender
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
Properties props = mailSender.getJavaMailProperties();
mailSender.setHost(this.emailCfg.getHost());
mailSender.setPort(this.emailCfg.getPort());
mailSender.setUsername(this.emailCfg.getUsername());
mailSender.setPassword(this.emailCfg.getPassword());
// Create an email instance
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(feedback.getEmail());
mailMessage.setTo("test#gmail.com");
mailMessage.setSubject("Testing mail");
mailMessage.setText(feedback.getFeedback());
mailSender.send(mailMessage);
}
This is caused by your server not responding with the proper headers. If you look at your network tab you will see and OPTIONS request that fires before your POST request. Your server needs to respond to that OPTIONS request to let the browser know its ok for the requesting client to access the resource. You can read more about it here at MDN but at the very least your server should respond to the preflight with headers like:
Access-Control-Allow-Origin: http://foo.example <== your domain here
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
#CrossOrigin(origins="http://localhost:9000")
#GetMapping("/hello")
public Greeting greeting() {
return "world";
}
or
#CrossOrigin(origins="http://localhost:9000", maxAge=3600)
#RestController
public class RestController {}

React fetch response missing Authorization header

I have some issues with CORS using React fetch and Spring Boot.
The React application runs on localhost:3000.
The Spring Boot backend runs on localhost:3001.
My problem is when I try to logging in using using fetch with the http://localhost:3001/login url the response in javascript does not contain the Authorization token.
The authentication on backend side works.
When I open the Chrome Inspector I can see the Authorization in the Network tab at the login request only it is missing in the javascript response.
The React fetch request look like the following: In the code the const userToken = response.headers.get('Authorization'); returns "null" string instead of the token.
return fetch("http://localhost:3001/login",{
method: 'post',
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
password
})
})
.then(
response => {
if(response.ok) {
const userToken = response.headers.get('Authorization');
return true;
}
// Error handling
}
);
The Spring Boot Security config is like the following:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable().authorizeRequests()
.antMatchers(HttpMethod.POST, REGISTRATION_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(// Auth Filter)
.addFilter(// Another auth Filter)
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
Another thing. When I used proxy: "http://127.0.0.1:3001" in the package.json the login worked and the React code above could read Authorization header. But I don't want to use proxy.

How to enable [Authorize] on TestController on IdentityServer4 for purpose of Claim CRUD Controller

Using OIDC Client from here.
And demo server from here and here.
I have the following controller on the IdentityServer itself:
[Route("api/Test")]
//[Authorize]
[Authorize(ActiveAuthenticationSchemes = "Bearer")]
public class TestController : ControllerBase
{
public IActionResult Get()
{
var claims = User.Claims.Select(c => new { c.Type, c.Value });
return new JsonResult(claims);
}
}
If I comment out both [Authorize] attributes, I reach the TestController.
If I use just [Authorize], I get the following error:
GET http://localhost:5000/api/Test dashboard:1 XMLHttpRequest cannot
load http://localhost:5000/api/Test. No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin
'http://localhost:4200' is therefore not allowed access. The response
had HTTP status code 500.
And if I just use [Authorize(ActiveAuthenticationSchemes = "Bearer")] I get:
GET http://localhost:5000/api/Test dashboard:1 XMLHttpRequest cannot
load http://localhost:5000/api/Test. No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin
'http://localhost:4200' is therefore not allowed access. The response
had HTTP status code 500. dashboard:1 XMLHttpRequest cannot load
http://localhost:5000/api/Test. Redirect from
'http://localhost:5000/api/Test' to
'http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2FTest' has been
blocked by CORS policy: Request requires preflight, which is
disallowed to follow cross-origin redirect.
The code I use to call the Endpoint from the OIDC client is:
test() {
this.authService.mgr.getUser()
.then(user => {
// this.http.get('https://api.identityserver.io/identity',
this.http.get('http://localhost:5000/api/Test',
{ headers: new Headers({ 'Authorization': `${user.token_type} ${user.access_token}`}) })
.subscribe(res => {
console.log(res.json());
});
});
}
I am able to successfully call https://api.identityserver.io/identity with this.
This is my CorsPolicyHelper:
public class DemoCorsPolicy : ICorsPolicyService
{
public Task<bool> IsOriginAllowedAsync(string origin)
{
return Task.FromResult(true);
}
}
And this is where its called form Startup:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AuthDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
...
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Resources.GetIdentityResources())
.AddInMemoryApiResources(Resources.GetApiResources())
.AddInMemoryClients(Clients.GetClients())
.AddAspNetIdentity<ApplicationUser>();
services.AddTransient<ICorsPolicyService, DemoCorsPolicy>();
}
Ultimate goal is to perform CRUD operations on permissions/claims. I am currently stuck on this seemingly trivial task of having an Authorization protected controller :/
Ultimately since I am able to to use [Authorize] successfully outside IdentityServer4, I decided to separate Authorization from Authentication and create an Authorization server which provides for separation of concerns.

Resources