CORS error on Axios PUT request from React to Spring API - reactjs

I am working on an update functionality using PUT. I have a React front end and Spring back-end API. Here is the following PUT request made from front-end:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {stuff})
}
Controller to handle this request:
#RestController
#CrossOrigin(origins="http://localhost:3000")
public class StuffController {
#Autowired
private StuffService stuffService;
#PutMapping(path="/stuff/{username}/{id}")
public ResponseEntity<Stuff> updateStuff(#PathVariable String username,
#PathVariable long id,
#RequestBody Stuff stuff) {
Stuff response = stuffService.save(stuff);
return new ResponseEntity<Stuff>(stuff, HttpStatus.OK);
}
I am able to use the same service for GET and DELETE. I am also able to send request using REST client. But when I am trying using browser I am getting this error in console:
Access to XMLHttpRequest at 'http://localhost:8080/stuff/abc' 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.
PUT http://localhost:8080/stuff/abc net::ERR_FAILED
Not able to figure out why its just happening for PUT request? How to resolve this? Appreciate your help and time!
EDIT:
Updated the front-end to:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {
headers:{
'Access-Control-Allow-Origin':'*',
'Content-Type': 'application/json;charset=UTF-8',
}
})
}
Still its throwing the same error. So far Spring Security is not configured. I am just checking a simple update flow without any authentication or authorization.
EDIT 2: Request headers in browser has Access-Control-Allow-Origin: *:

I ran into a similar issue a while ago. Check if the variables of your model class in the backend have the same name as in your frontend. That fixed it for me.

The best way to deal with this cors policy is to add a proxy field in the pakage.json file.enter image description here

In reactjs application you can use your spring boot api's URL as proxy to avoid CORS issue.
package.
package.json
{
"proxy": "http://localhost:8080/",
"dependencies": {
.
.
.
}
}
axios
Axios.put(stuff/${username}, {stuff})

Related

Spring method with React front

Hi i'm trying to create small project with React Front and Spring Java backend.
Let's say in Spring Controller class i have a method:
#CrossOrigin(origins = "http://localhost:3000/")
#GetMapping("/something")
public void printSomething()
{
System.out.println("examplePhrase");
}
In React i have a form with button that invoke method 'handleSpring' looks like:
handleSpring = e =>
{
e.preventDefault();
console.log("Method started");
const SpringAPI = `http://localhost:8080/something`
fetch(SpringAPI, {})
.then(response => console.log("method works"))
.catch(err => console.log("method failed"))
}
When i run both application and go to "localhost:8080/something" i have a message in Intellij console "examplePhrase" so Spring method works. When i'm going to "localhost:3000", i have my form made by React. But when i right-click on this site, choose "inspect" -> "console" in browser menu, and next press form button i have an error:
method started
localhost/:1 Access to fetch at 'http://localhost:8080/something' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
App.js:50 GET http://localhost:8080/something net::ERR_FAILED
App.js:50 method failed
I tried to add "no cors" to fetch but it doesn't change anything. Can anybody tell me how i could fix that?
A trailing slash in cors origin is causing the error.
#CrossOrigin(origins = "http://localhost:3000") // no slash at end in origin.
Hope this fixes your issue.

Access to XMLHttpRequest blocked by CORS Policy in ReactJS using Axios

I'm setting up stripe connect button in my React Component using Axios. I keep getting this error after redirection
Access to XMLHttpRequest at 'https://connect.stripe.com/oauth/token' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
Thankyou.js:40 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
I get the code from the url and create a curl request using axios.Post. This is the code in my redirect URL
// Thankyou.js
export default class Thankyou extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const code = qs.parse(this.props.location.search, {
ignoreQueryPrefix: true
}).code;
const params = {
client_id: "*******************",
client_secret: "**********************",
grant_type: "authorization_code",
code: code
};
axios
.post(
"https://connect.stripe.com/oauth/token",
// apiBaseUrl,
{ params }
)
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
console.log(code);
}
render() {
return (
<div>
<h2>Thank you for connecting with us!</h2>
</div>
);
}
}
There is nothing wrong with your code, but most likely the API endpoint the code trying to reach is not setup for JavaScript web app. CORS policy is set on the server-side and enforced primarily on the browser-side.
The best way to work around is to use Stripe's JavaScript solution such as Strip React Elements or Stripe.js.
A hacky way to get around CORS would be setting up Reverse proxy with solutions such as NGINX. For example, you can use the following nginx configuration:
server {
listen 8080;
server_name _;
location / {
proxy_pass http://your-web-app:2020/;
}
location /stripe/ {
proxy_pass https://connect.stripe.com/;
}
}
By doing so, all the API calls to Stripe.com could be through /stripe under your web app's URL. For example, calling http://yourapp/stripe/oauth/token would be same as calling https://connect.stripe.com/oauth/token
That being said, the second solution is hacky and Stripe may decide to block your reverse proxy server.
basically you need to talk to whoever is hosting this https://connect.stripe.com/oauth/token to enable CORS (Cross Origin Resource Sharing )
It is a security measure implemented by most standard browsers to stop unwanted requests to your backend
It's probably because Stripe doesn't provide JavaScript client so you either have to use your own server proxy or use something like "https://cors-anywhere.herokuapp.com/https://connect.stripe.com/oauth/token"
I hope this answer would be useful to new users:
This issue can be easily fixed by using an annotation in your spring boot rest controller class.
Something like below (also ref screenshot):
#CrossOrigin(origins = "http://localhost:4200")
Explicitly mention the react JS server URL that is causing this issue.
Now after adding above annotation (with your react JS server URL) the browser will allow the flow.
All the best.
Learn about CORS
Think about it, there is anything wrong with your axios.post request, it's successfully contacting the server. But there is one more thing to do before the server let you execute or manipulate it's files.
For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy.
So your cross-origin request and the server Cross-Origin Resource Sharing (CORS) have to match.
How do you solve it?
Depending on your server and the server side programming language your are implementing, you can configure the different parameters to handle your CORS.
For example, you can configure that the only allowed methods will be:
GET HEAD
So if someone try to axios.post to your server with a different method like POST, it will return an error like this:
Access to XMLHttpRequest at 'https://connect.stripe.com/oauth/token' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
Thankyou.js:40 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Resources:
https://www.w3.org/TR/cors/
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
I would suggest reading through this site: https://stripe.com/docs/recipes/elements-react
It gives specific instructions straight from stripe on using their API with react. Good luck!

Keycloak CORS issue associated with login redirect

Similar questions here and here have not helped me resolve the problem.
I am using Keycloak 4.4.0 to secure my REST service, which is implemented using Spring Boot and I am using React for the front end.
I get a CORS error when the front end (running on localhost:3000) makes an API call to localhost:8080/login and is redirected to the Keycloak login page.
The error is:
localhost/:1 Failed to load http://localhost:8080/login: Redirect from 'http://localhost:8080/login' to 'http://localhost:9080/auth/realms/hbs/protocol/openid-connect/auth?response_type=code&client_id=hbs&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&state=ab5034a9-4baa-4be3-9ec1-feefbe5f9c0b&login=true&scope=openid' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
I have added a single value of '*' to the Web Origins config section in the Keycloak client.
I have annotated my REST controller as follows:
#RestController
class MyController
{
#CrossOrigin
#GetMapping("/login")
public ResponseEntity<Foo> getFoo(Principal principal)
{
return ResponseEntity.ok(new Foo("blah"));
}
}
I have enabled Keycloak and CORS in the application properties:
keycloak.cors = true
keycloak.enabled = true
If I disable Keycloak and CORS, problem goes away.
As described here, I suspect the issue is to do with the Keycloak server not responding with any Access-Control-Allow-Origin headers despite Web Origins being correctly configured in the Keycloak admin portal. But I'm not completely sure how to confirm this.
Imagine the following json below is your Keycloak configuration:
{
"realm" : "cors",
"resource" : "cors-database-service",
"auth-server-url": "http://localhost-auth:8080/auth",
"bearer-only" : true,
"ssl-required": "external",
"enable-cors": true
}
Try adding the last line to your configuration file.
Let me know if it worked for you!
OBS: I'm facing the same issue, but I'm using Wildfly/JBOSS adapters and making this configuration inside the application server.
#EDIT:
This worked fine for me.
Try changing the "Access Type" to bearer-only inside your REST Client on Keycloak.
Also, don't forget to add the parameter {"{"Authorization" : "bearer " + $TOKEN} when sending HTTP requests from your client to your RESTful API.
For those encountering this error with spring. Just add this class to your project to allow cors:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class CorsConfig implements WebMvcConfigurer {
String[] origins = new String[] { "http://localhost:8081"};
#Override
public void addCorsMappings(CorsRegistry registry) {
System.out.println("TEST TEST");
registry.addMapping("/**")
.allowedOrigins("*");
// .allowedOrigins(origins);
}
}
The asterisk allows all origins, which may not be secure for productive systems. A string array can be used to specify more than one origin.

How do I get react-stormpath to add Access-Control-Allow-Origin headers?

I'm having a similar problem to:
401 Error with post request Stormpath Express + React + Node + Gulp
Specifically, when I try to use the LoginForm or RegisterForm from react-stormpath, I get:
XMLHttpRequest cannot load https://api.stormpath.com/v1/applications/[ID]/oauth/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
I have added http://localhost:3000 to the Authorized Origin URIs in the Stormpath console, but that doesn't help. I've inspected the request using Chrome, and indeed, there is no ACAO header coming back.
Unlike the other issue linked to above, I'm not doing anything custom. My login page just looks like this:
import React from 'react';
import { LoginForm } from 'react-stormpath';
export default class Login extends React.Component {
render() {
return (
<LoginForm />
);
}
}
I don't even know how to debug this issue because I don't know what's going on under the hood in react-stormpath.
Edit: Adding the react-stormpath config:
ReactStormpath.init({
endpoints: {
baseUri: 'https://api.stormpath.com/v1/applications/[ID]'
}
});
The problem is in your ReactStormpath.init. Your React app can't connect to api.stormpath.com directly, because that requires using a secure API key. Your baseUri should instead be one of:
Your Stormpath application's Client API URL, like https://foo-bar.apps.stormpath.io. This is a separate API domain that allows untrusted clients (like React) to connect. This part of the documentation is a better example.
Your web server, like http://localhost:3000 - if you are using something like express-stormpath (I can't quite tell from your question)
Disclaimer: I work at Stormpath.

CORS problems with Spring-security

I am building an app with Spring-boot (on http://localhost:8080) and angular (on http://localhost:80).
the frontend and backend code are served by 2 different servers. In order to avoid CORS problems, I used to put in place an intermediate nginx server but I am not satisfied with this solution anymore. Hence, I have to allow CORS.
I allowed CORS globally with those lines :
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost")
.allowCredentials(true)
;
}
}
This works for every routes except for the authentication route which is handled with Spring security :
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(successHandler())
.failureHandler(failureHandler())
//[...]
}
private AuthenticationSuccessHandler successHandler() {
return (httpServletRequest, httpServletResponse, authentication) ->
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
}
private AuthenticationFailureHandler failureHandler() {
return (httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
};
}
Here is the code that sends the request on the frontend part :
$http.post('http://localhost:8080/api/login', $.param({'username': username, 'password': password}),
{headers: {'content-type': 'application/x-www-form-urlencoded'}}
).then(function() {})
.catch(function(error) {};
If I enter the correct password, the http response code (that I can see in the Chrome console) is 200 but I still reach the catch block (with error.status = -1) and I can see this error message in the console :
XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
If I enter the wrong password I also reach the catch block with this error message :
XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 401.
I also notice that CORS response headers are missing when I call the authentication endpoint.
Any ideas?
EDIT : it works if I manually add headers in the custom success handler. I would prefer if Spring-security could take into account the global CORS configuration.
From my experience you'll need to include the port number in CORS, the error message from the browser is a bit misleading.
You can verify that by inspecting network and check the Origin field of your request headers. The value in Access-Control-Allow-Origin of your response headers must match that exactly including protocol and port.
You should take a look on Spring website. There are solutions for consuming web service and managing CORS :
Enabling Cross Origin Requests for a RESTful Web Service : https://spring.io/guides/gs/rest-service-cors/
Consuming a RESTful Web Service with AngularJS : https://spring.io/guides/gs/consuming-rest-angularjs/
Had the exact same issue two thing you could do,
#CrossOrigin(origins = "http://localhost:8080") add this to the service methods. The idea behind this is you enable CORS request through your service itself.
Use JSONP, but this has certain limitation. Also i wasnt successful in implementing it, so i used the above option.

Resources