CORS blocking post requests in javascript - 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

Related

Why is the response body empty (0 bytes on network tab) for this request? Is it to do with this being an extension?

When I use the fetch API (Or xmlhttprequest) I get a 0 byte response. Here is a sample of my code:
fetch("https://myurl", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({content: content})
}).then(function(res){ return res.text()}).then(function(res){ return cb(res);});
In the network tab, and in the console.log(res) in the callback, the response is empty. I should note that the response is including a CORS response specifying my chrome extension (which is making the request)
Access-Control-Allow-Origin: chrome-extension://asdjkljuewyrjkhighqwend
When I use the requests library (python) and make the same request (copying and pasting the body of the request) I get a valid json response.
resp = requests.post("https://myurl", json=data)
resp.json() ->> {content}
Additionally, when I inspect the server after the Fetch requests, I can see that it happily responded with the json to the request, but something on the browser seems to be blocking it from getting through.
You need to move all XHR requests to the background part of your extension.
Chrome no longer accepts content scripts requests.
You can use runtime.sendMessage to send messages to a background process.
chrome.runtime.sendMessage(myMessageObject, async response => {
// Here is the response returned by the background process
});
And here is how to receive messages from the background perspective.
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
return true
})
I believe you're indeed looking at a CORS issue. Try including the following headers in the response from your server:
Access-Control-Allow-Origin: * // you already hve this one
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, PUT, POST, OPTIONS

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

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..

Request header field Access-Control-Request-Methods is not allowed by Access-Control-Allow-Headers in preflight response

I'm trying to send a POST request from my website to my remote server but I encounter some CORS issues.
I searched in the internet but didn't find a solution to my specific problem.
This is my ajax request params:
var params = {
url: url,
method: 'POST',
data: JSON.stringify(data),
contentType: 'json',
headers: {
'Access-Control-Request-Origin': '*',
'Access-Control-Request-Methods': 'POST'
}
On the backend side in this is my code in python:
#app.route(SETTINGS_NAMESPACE + '/<string:product_name>', methods=['POST', 'OPTIONS'])
#graphs.time_method()
def get_settings(product_name):
settings_data = helper.param_validate_and_extract(request, None, required=True, type=dict, post_data=True)
settings_data = json.dumps(settings_data)
response = self._get_settings(product_name, settings_data)
return output_json(response, requests.codes.ok, headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST'
})
I get an error on my console:
XMLHttpRequest cannot load [http://path-to-my-server]. Request header field
Access-Control-Request-Methods is not allowed by
Access-Control-Allow-Headers in preflight response
I did notice that I can add also 'Access-Control-Request-Headers' but I wasn't sure if it necessary and it cause me more problems so I removed it.
Does anyone know how to solve this problem?
Your ajax request shouldn't send Access-Control headers, only the server sends those headers to allow the servers to describe the set of origins that are permitted to read that information using a web browser.
The same-origin policy generally doesn't apply outside browsers, so the server has to send CORS headers or JSONP data if the browser is going to be able to get the data.
The browser doesn't send those headers to the server, it doesn't have to, it's the server that decides whether or not the data is available to a specific origin.
Remove the header option from the params object, and it should work

Fetch PATCH request not allowed (CORS)

So I've been using fetch for quite a while without any issues. I've created plenty of APIs and had to implement CORS in multiple APIs.
However, today I can't seem to get CORS to work for a single patch request. It works for get/post/delete without issues, but patch isn't working.
I have read fetch patch request is not allowed, and sadly I already wrote patch fully capitalized, so this isn't a solution for me.
My request:
{
method: 'PATCH', //using POST here makes everything work fine.
json: true,
headers: defaultHeaders,
body: JSON.stringify({
type: 'analytics_analyzers',
attributes: {
status: active ? 1 : 2,
ssid: getState().config.ssid
}
})
}
And the server's .htaccess file:
SetEnvIf Origin "http(s)?://(www\.)? (whitelistUrl1|whitelistUrl2|whitelistUrl3)$" AccessControlAllowOrigin=$0
Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Credentials true
SetEnvIf Access-Control-Request-Headers ".*" AccessControlHeaders=$0
Header always set Access-Control-Allow-Headers: %{AccessControlHeaders}e env=AccessControlHeaders
SetEnvIf Access-Control-Request-Method ".*" AccessControlMethod=$0
Header always set Access-Control-Allow-Methods: %{AccessControlMethod}e env=AccessControlMethod
Options request
Error message
Anyone has any ideas to what I'm doing wrong here?
In fact, when we send a not simple cors request to server side, like DELETE/ PUT / PATCH, but not include POST/GET/HEAD,the browser will send a OPTIONS request (preflight) to server side then ask if it is support the METHOD/ORIGIN/HEADERS, so if you just specified the PATCH request allowed method is not enough.
It's my example codes, just for this question, may be not so grace,hope u never mind ...
app.patch('/cors', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Server,Date,access-control-allow-methods,access-control-allow-origin");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.send('ok')
})
app.options('/*', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Server,Date,access-control-allow-methods,access-control-allow-origin");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.send('send some thing whatever')
})

CORS Post Request Fails

I built an API with the SLIM Micro-Framework. I setup some middleware that adds the CORS headers using the following code.
class Cors{
public function __invoke(Request $request, Response $response, $next){
$response = $next($request, $response);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
}
}
For my front-end, I used VueJS. I setup VueResource and created a function with the following code.
register (context, email, password) {
Vue.http({
url: 'api/auth/register',
method: 'POST',
data: {
email: email,
password: password
}
}).then(response => {
context.success = true
}, response => {
context.response = response.data
context.error = true
})
}
In chrome, the following error is logged to the console.
XMLHttpRequest cannot load http://mysite:9800/api/auth/register. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mysite' is therefore not allowed access.
Oddly enough, GET requests work perfectly.
You half 1/2 the solution here.
What you are missing is an OPTIONS route where these headers need to be added as well.
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
});
This happens because preflight request is of OPTIONS type. You need to make an event listener on your request, which checks the type and sends a response with needed headers.
Unfortunately i don't know Slim framework, but here's the working example in Symfony.
First the headers example to be returned:
// Headers allowed to be returned.
const ALLOWED_HEADERS = ['Authorization', 'Origin', 'Content-Type', 'Content-Length', 'Accept'];
And in the request listener, there's a onKernelRequest method that watches all requests that are coming in:
/**
* #param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
// Don't do anything if it's not the master request
if (!$event->isMasterRequest()) {
return;
}
// Catch all pre-request events
if ($event->getRequest()->isMethod('OPTIONS')) {
$router = $this->container->get('router');
$pathInfo = $event->getRequest()->getPathInfo();
$response = new Response();
$response->headers->set('Access-Control-Allow-Origin', $event->getRequest()->headers->get('Origin'));
$response->headers->set('Access-Control-Allow-Methods', $this->getAllowedMethods($router, $pathInfo));
$response->headers->set('Access-Control-Allow-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Expose-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Allow-Credentials', 'true');
$response->headers->set('Access-Control-Max-Age', 60 * 60 * 24);
$response->send();
}
}
Here i just reproduce the Origin (all domains are allowed to request the resource, you should probably change it to your domain).
Hope it will give some glues.
Actually CORS is implemented at browser level. and Even with
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
chrome and Mozilla will not set headers to allow cross origin. So, you need forcefully disable that..
Read more about disabling CORS
Disable same origin policy in Chrome
CORS can be hard to config. The key is that you need to set the special headers in your server and your client, and I don't see any Vue headers set, besides as far as I know http is not a function. However here is some setup for a post request.
const data = {
email: email,
password: password
}
const options = {
headers: {
'Access-Control-Expose-Headers': // all of your headers,
'Access-Control-Allow-Origin': '*'
}
}
Vue.http.post('api/auth/register', JSON.stringify(data), options).then(response => {
// success
}, response => {
// error
})
Notice that you need to stringify your data and you need to expose your headers, usually including the Access-Control-Allow-Origin header.
What I did in one of my own apps was to define interceptors so I don't worry to set headers for every request.
Vue.http.headers.common['Access-Control-Expose-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, x-session-token, timeout, Content-Length, location, *'
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'

Categories

Resources