Cross-Origin Request Blocked between Node dev server and Spring Boot application - javascript

My stack is as follows:
Backend: Spring boot(Java) exposed at :8088
Frontend: Vue hosted on a Node development server exposed at :8080
On the frontend, I am re-configuring axios in a http-common.js to put the baseURL to the Spring boot application, and allow connection from the node development server:
import axios from 'axios'
export const AXIOS = axios.create({
baseURL: `http://localhost:8088`,
headers: {
'Access-Control-Allow-Origin': 'http://localhost:8080'
}
})
However, when attempting to make a post request to log in, I will get the following message in the console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8088/api/login. (Reason: CORS preflight channel did not succeed).
Which makes me think: Is the issue with the spring boot application?
But no, in the main method, I have enabled CORS globally when reaching the /api/* endpoints from the node application running at :8080:
#Bean
public WebMvcConfigurer corsConfigurer() { // Enables CORS globally
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*").allowedOrigins("http://localhost:8080");
}
};
}
To me it looks as if it should be configured correctly. However, as of now, the following POST of username + password never even reaches the backend Spring boot application at all. The issue must be with the Node application?
This is the Login method in the frontend:
login ({commit}, authData) {
AXIOS.post('/api/login', {
username: authData.username,
password: authData.password,
withCredentials: true
})
.then(res => {
console.log(res)
commit('authUser', {
token: res.data.idToken,
userId: res.data.localId
})
})
.catch(error => console.log(error))
}
To further solidate my point, i can cURL to the spring boot application and get the correct response(a valid JWT!):
Request:
curl -i -H "Content-Type: application/json" -X POST -d '{
"username": "sysadmin",
"password": "sysadmin"
}' http://localhost:8088/api/login
Response:
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
X-Application-Context: application:8088
authentication: <very long JWT string>
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
So, via cUR - I get a HTTP 200 OK, and a valid JWT. But via the same POST method from :8080, I get a 403 and a warning message.
As per other posts, I have attempted to add CORS to my dev server configuration(Node/Express):
var app = express()
app.use(cors())
app.options('*', cors())
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8088')
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE')
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type')
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true)
// Pass to next layer of middleware
next()
})
The result is exactly the same as previously

Adding the 'Access-Control-Allow-Origin' header to your ajax post call is useless since is part of cors specification and must be set by the server as part of the http response.
export const AXIOS = axios.create({
baseURL: `http://localhost:8088`,
headers: {
//you can remove this header
'Access-Control-Allow-Origin': 'http://localhost:8080'
}
})
You can curl the application because the cors exception is caused by the browser disallowing you to access the payload. The browser performs the preflight (OPTION) request before any Cross domain call, and before your actual http request to make sure you have the rights to see the payload, you can see it just inspecting the console under the network tab.
the issue is most likely server side, somehow you did not configure correctly the cors header to your http response.
make sure you're setting not only the Access-Control-Allow-Origin header (that must contain the specific domain, not * since you're in credential mode), but even Access-Control-Allow-Credential since you're sending credentials, and the Access-Control-Allow-Methods (that must contain at least the PUSH and the OPTION methods)
in your chrome dev tools console under the network tab if you inspect your ajax call you can see the header of the http response, should end up with something like this.

Have you tried to add #CrossOrigin to your login REST method?
#CrossOrigin(origins = "http://localhost:8080")
#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));
}
Update: I just read this on javadoc:
Exact path mapping URIs (such as "/admin") are supported as well as Ant-style path patterns (such as "/admin/**").
I don't see here a path with one star, but your path is a correct Ant-style path..

Related

How to bypass CORS policy when sending get/post request from React JS?

From my React JS app , I need to fetch data from servers in other domains.
However, I am prevented by CORS policy and not able to fetch the data.
Let us assume that my React app is running on localhost:3000 during the development.
I want to make get/post call to another server running on http://myserver.com
The URL through which I want to fetch the data is http://ext-server.com/data/records?name=xyz
I have installed http-proxy-middleware thru npm and using it in my react app.
Created a setupProxy.js file under src folder with below content :
const { createProxyMiddleware} = require("http-proxy-middleware")
module.exports = app => {
app.use(
createProxyMiddleware('/data/records' , {
target:'http://ext-server.com',
changeOrigin: true
})
)
}
On the landing page of my react app (firstpage.js) when http://localhost:3000 is hit , I have added below piece of code to the button event that makes the get call to the http://ext-server.com
getTheData() {
let url = "http://ext-server.com/data/records?name=" + encodeURIComponent(this.state.name);
axios.get(url,
{
headers: {
"Content-Type":"application/json;charset=UTL-8",
"Access-Control-Allow-Origin": "*",
Accept: "application/json",
},
baseURL: 'http://ext-server.com'
}
).then((response) => {
console.log(response["access_token"]);
}).catch(error) => {
console.log("Error: ", error)
}).then(function () {
console.log("always call it")
});
}
In the package.json , I have added :
"proxy": "http://ext-server.com",
"homepage":"http://localhost:3000",
But I am still getting below error:
Access to XMLHttpRequest at 'http://ext-server.com/data/records?name= ' from origin 'http://localhost:3000' has been blocked by CORS policy.
Is there anything that I am missing here ? what is the correct way to use this http-proxy-middleware?
Any help will be very useful!
Thanks
As you can see from MDN the "Access-Control-Allow-Origin": "*" header is a response type header, this means that it should go to in your server response. Also I advise you to not use the * symbol, instead I would rather match it with the origin header in your Request.
The CORS policy is one and only administered by the web server and its settings. To allow CORS requests it has to be implemented on server side. No chance to do it from your client application.
Basically its just a header setting (below example for NodeJS):
res.header("Access-Control-Allow-Origin", "*")
Sending that header will allow requests from every domain.

CORS blocking post requests in javascript

im making an api using Javalin and trying to send data to it from javascript, however i get cors errors whenever i try to do so. i can recieve data just fine but not send data. Here is my error: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
-----------javascript-----------
function sendOurAjax(){
console.log("ajax using fetch")
let ourCustomSuper = {
"name": "SpaceMonkey",
"superpower": "person atmosphere",
"bounty": 0
}
fetch(`http://localhost:8000/api`, {
method: "post",
'headers': {
'Content-Type': 'application/json',
'BARNACLES': 'custom header value'
},
'body': JSON.stringify(ourCustomSuper)
})
.then(
function(daResponse){
console.log(daResponse);
const convertedResponse = daResponse.json();
return convertedResponse;
}
).then(
function(daSecondResponse){
console.log("Fetch is a thing. We did it.");
console.log(daSecondResponse);
}
).catch(
(stuff) => {console.log("this sucker exploded")}
)
}
-----------java-----------
app.get("/api", context ->{
context.header("Access-Control-Allow-Origin", "*");
context.header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
context.header("Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token");
System.out.println("The endpoint method has fired");
context.result("endpoint handler has fired");
context.json(myList);
});
Why was the CORS error there in the first place?
The error stems from a security mechanism that browsers implement called the same-origin policy.
The same-origin policy fights one of the most common cyber attacks out there: cross-site request forgery. In this maneuver, a malicious website attempts to take advantage of the browser’s cookie storage system.
For every HTTP request to a domain, the browser attaches any HTTP cookies associated with that domain. This is especially useful for authentication, and setting sessions. For instance, it’s feasible that you would sign into a web app like facebook-clone.com. In this case, your browser would store a relevant session cookie for the facebook-clone.com domain:
here a link on the cors subject
How To Fix CORS Error
Offhand is see you do have the
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://localhost:3000
set but the content type might be wrong i.e json
something along the lines of
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Content-Type: application/json

axios delete call returns 405

We are running a Tornado service in the background which accepts post and delete calls from the React application.
Our axios.post call works perfectly fine but it fails on our delete request with the following error message
405 (Method Not Allowed)
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.
export const StopBuild = (action$) =>
action$.ofType(STOPBUILD)
.mergeMap((action) => {
return Observable.fromPromise(axios.delete(action.stopRequest))
.map(response => PlatformBuildSuccess(response))
.catch(error => Observable.of(PlatformBuildFailure(error, action.platform)))
})
From server side, this is what we have currently set,
self.set_header("Content-Type", "*")
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header("Access-Control-Allow-Headers", "*")
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE')
Something else we noticed that when on the server side we only set the following header POST call still works. I think we are going wrong on the server end.
self.set_header("Access-Control-Allow-Origin", "*")
Any help would be appreciated.
What you can do is, allow cors in your API request:
Like this :
axios.delete(url, { crossdomain: true }) // an example
you can take this as an example and add crossdomain:true in your delete request.
let me know if cors error still persists.
This is a CORS issue. As the error states it, the DELETE operation is not allowed yet. Here is explained that you have to add the DELETE method to the Access-Control-Allow-Methods response header of the preflight request.
On server side, using nodejs, allowing CORS would look like this:
const corsMiddleware = (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', '*')
res.header('Access-Control-Allow-Methods', 'OPTIONS, POST, DELETE')
next()
}
app.use(corsMiddleware)
The request can be made from all origins with all headers, and OPTIONS, POST and DELETE methods are allowed.
For CORS request there is one package available called cors. You can try that by installing it as,
npm install cors --save
then you can require it and use that as middleware here the example,
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
More on cors npm package here

5xx or 4xx error with “No 'Access-Control-Allow-Origin' header is present”

My browser is logging the following message in the devtools console:
No 'Access-Control-Allow-Origin' header is present on the requested resource.… The response had HTTP status code 503.
Background: I have two apps. One that is an Express Node application connected to a Mongo database. The other is a basic web application that makes POST requests to the Node application via the Fetch API to get data from Mongo.
Issue: Though I receive no CORS errors on my local machine, I am given the error below as soon as I deploy my basic web application to production. The web application that makes a POST request to the Node app and gives me this:
The POST request does seem to work and the data is saved into Mongo but this error is being marked as a "Critical Error" in Heroku and is quite annoying.
I realize that I could set the no-cors option in Fetch but I believe that it is required since I am making a request to a url that is different than the origin. Right?
Express Node App Code
In my app.js file I have set the correct headers to ensure that other applications can make requests from different origins
app.js
// Add headers so we can make API requests
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
routes/api/api.js
router.post('/users/:url/upload-csv/:csv_name', (req, res) => {
let csv_name = req.params.csv_name;
let csv_string = csv_name+req.body.csv_string;
User.findOne({url: req.params.url})
.then((user) => {
if (user.csv_files.length === 0) {
user.csv_files.push(csv_string);
} else {
let foundExistingCSV = false;
for (var i = 0; i < user.csv_files.length; i++) {
if (user.csv_files[i].includes(csv_name)) {
foundExistingCSV = true;
user.csv_files[i] = csv_string;
break;
}
}
if (!foundExistingCSV) user.csv_files.push(csv_string);
}
user.markModified('csv_files');
user.save();
res.status(204);
})
.catch((err) => {
console.log(err);
res.status(400);
});
});
Basic Web App Code
POST request I am making
utils.js
utils.exportToMongo = functions(table, name) {
var exportPlugin = table.getPlugin('exportFile');
var csv_string = exportPlugin.exportAsString('csv');
// Upload the CSV string and its name to Users DB
fetch(`${utils.fetchUserURL()}/upload-csv/${name}`, {
method: 'POST',
body: JSON.stringify({csv_string: csv_string}),
headers: new Headers({
'Content-Type': 'application/json',
Accept: 'application/json',
})
}).then((res) => {
return {};
}).catch((error) => {
console.log(error);
return {};
});
}
How can I remove the 503 error? Any insight would be greatly appreciated!
An HTTP 5xx error indicates some failure on the server side. Or it can even indicate the server just isn’t responding at all — e.g., a case might be, your backend tries to proxy a request to a server on another port, but the server is not even be up and listening on the expected port.
Similarly, a 4xx indicates some problem with the request prevented the server from handling it.
To confirm, you can try making the same request using curl, or Postman, or something, and see if you get a 2xx success response for the request, rather than a 5xx or 4xx.
Regardless, if you see a 5xx or 4xx error on the client side, some message should get logged on the server side to indicate what failed and why. So to identify what triggered the 5xx/4xx error, check server logs to find messages the server logged before it sent the error.
As far as CORS error messages go, it’s expected that in most cases for a 5xx or 4xx error, servers won’t add the Access-Control-Allow-Origin response header to the response; instead the server most likely will only send that header for 2xx and 3xx (redirect) responses.
So if you get the cause of an 5xx/4xx error solved such that you can get a success response, you may find your CORS config is already working fine and you’ve got nothing left to fix.
I had the same issue, the server doesn't support cross origin request. The API developer should change Access-Control-Allow-Origin to * (means from any origin).sometimes jsonp request will bypass, if its not working, google chrome provides plugins to change origin
plugin

Failed to fetch: Request requires preflight, which is disallowed to follow cross-origin redirect

I'm using Express for webserver, and using isomorphic-fetch module from client to using XHR.
I have three servers for my web application:
Port 3000 -> Admin Website
Port 3001 -> Public Website
Port 3002 -> API Server
API Server has resources named "skills" which has some data, and get it like this:
GET http://mydomain:3002/skills
it returns JSON data.
But when I request to 3002 from 3000/3001, it fails with this message:
Fetch API cannot load http://example.me:3002/skills. Redirect from 'http://example.me:3002/skills' to 'http://example.me:3002/skills/' has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.
I don't get it why there is 'redirection' or something. This is my server side code, I granted all CORS related headers:
const express = require('express');
const app = express();
...
// CORS
app.use((req, res, next) => {
var allowedOrigins = ['http://example.me', 'http://example.me:3000', 'http://example.me:3001', 'http://example.me:3002'];
var origin = req.headers.origin;
if(allowedOrigins.indexOf(origin) > -1){
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
if (req.method === "OPTIONS") {
return res.status(200).end();
}
next();
});
app.use(require('./routes'));
...
app.listen(3002, () => console.log(".API Server listening on port 3002..."));
And this is client side code that using Fetch API:
fetch('http://example.com:3002/skills', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
credentials: 'include',
cache: 'no-store',
mode: 'cors'
})...
As you can see there is no redirection code. I spent almost a day to fix this issue, but everything I tried was all failed, every information that I found was useless.
I think splitting services to API Server and Web Server(actually returns HTML) was good idea, and want to go with this approach.
Is there a way to fix this problem? Any advice will very appreciate.
I solved this issue few years ago, still don't get it why it happened.
However my solution was simple, put every API into /api path.

Categories

Resources