I'm trying to request a rest API that needs authentication with a token. When constructing the Request object, some headers disappear.
Why can't I set my Authorization header ?
let http_headers = {
"Content-type": "application/json",
'Authorization': 'Token token='+my_token,
'Accept': 'Application/json'
};
let url = this.base_url + '/api/v1/test';
let init = {
method: "POST",
headers: new Headers(http_headers),
mode: 'no-cors',
credentials: 'omit' // I try that, but it doesn't seem to have effect
};
let req = new Request( url, init );
console.log(req.headers.get("Accept")); // Application/json
console.log(req.headers.get("Authorization")); // null, why ?
See the documentation for mode
no-cors — Prevents the method from being anything other than HEAD, GET or POST, and the headers from being anything other than simple headers. If any ServiceWorkers intercept these requests, they may not add or override any headers except for those that are simple headers. In addition, JavaScript may not access any properties of the resulting Response. This ensures that ServiceWorkers do not affect the semantics of the Web and prevents security and privacy issues arising from leaking data across domains.
Set the mode to same-origin or cors to allow credentials to be set.
You probably want to use the fetch function and set the headers in the options parameter.
fetch(url, { //fetch options
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, cors, *same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json",
// Your headers here
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
})
.then(); // parse response
Borrowed from https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
The fetch function returns a Promise that will have the Response object containing data from your api.
Related
I am sending POST request like this from browser and it is a cross platform request:
var reg_data = {"name": "John"};
fetch(url, {
method: 'POST',
mode: 'no-cors',
headers: new Headers({
'Content-Type': 'application/json',
'token': 'value'
}),
body: JSON.stringify(reg_data)
})
By the time the request reaches my back-end it does not contain token nor body.
Following is my backend ruby code -
before_action :cors_preflight_check
def cors_preflight_check
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Accept, Content-Type, token'
end
I checked some articles it says it happens as the mode is set to "no-cors" the headers and body is restricted. It works fine with postman, but fails with browser. How do I solve this issue as I want to serve a cross platform request and also access the request headers and body?
I can't enable CORS on the server-side. My frontend and backend servers have different ports. Here is how server-side is implemented:
http
.createServer(function (req, res) {
// .. Here you can create your data response in a JSON format
// const { headers, method, url } = req;
// let body = [];
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
// const responseBody = { headers, method, url, body: JSON.stringify(data) };
response.write('{asd: 123}'); // Write out the default response
res.end(); //end the response
})
.listen(port);
And I call the fetch function from the frontend-side like this one:
fetch('http://localhost:3035', {
method: 'POST',
mode: 'same-origin', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'include', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify(line), // body data type must match "Content-Type" header
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.log(error));
But still getting errors:
Security Error: Content at http://localhost:3030/ may not load data from http://localhost:3035/.
TypeError: "NetworkError when attempting to fetch resource."
You explicitly disallowed CORS on the client side by setting mode: 'same-origin' instead of the default mode: 'cors'.
To quote the docs:
same-origin — If a request is made to another origin with this mode set, the result is simply an error. You could use this to ensure that a request is always being made to your origin.
Since http://localhost:3035/ is another origin than http://localhost:3030/, the result is, exactly as designed, "simply an error".
Set it to mode: 'cors' or remove mode entirely since cors is the default anyway.
On a side note, Access-Control-Request-Method is a request header in the preflight request, not a response header. You should remove it.
As mentioned in the comments: For a credentialed request to work, you cannot use an allowed origin of *. If you don't want to hardcode the expected origin at this point though, you can avoid this problem by always returning the origin that the current request comes from, using res.setHeader('Access-Control-Allow-Origin', req.headers.origin).
I'm having problems with cookie authentication between an expressJS server and a VueJS font-end.
When logging in through the site, I successfully get a HTTPOnly Cookie in the set-cookie header:
Screenshot (Ignore the Auth header, using it for testing only)
I also see the cookie in the devTools, and everything looks right too me, I'm not an expert on cookies though so it may not be correct
The problem is when I request the user's settings on another endpoint, the cookie is not sent to the server. The req.cookie object is empty when the this request is handled on the server side.
Here is my fetch code:
const loginOptions = {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
}),
credentials: 'same-origin',
};
const settingsOptions = {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
credentials: 'same-origin',
};
const loginResponse = await fetch(baseUrl + '/login', loginOptions);
const userSettings = await fetch(baseUrl + '/settings', settingsOptions);
I've tried using credentials: "include", without success.
On the express server I'm using cors like this:
app.use(cors({
origin: '*',
credentials: true,
}));
Here is also an example of the second request, the 403 status is set by the server when no cookie is attached to the request.
I've tried setting the domain of the cookie to both localhost and 127.0.0.1 as suggested in another thread. I have left it on localhost for now.
Solved
I had read somewhere that you should add a specific domain value to the cookie when creating it. If I just removed that setting, it sets it automatically I'm guessing, and then it worked! So my guess is that I had set the domain value to the wrong value for what I was trying to do
Your response has access-control-allow-origin: http://localhost:8080 which implies you are making a cross-origin request.
You said:
credentials: 'same-origin',
… which tells your client-side code to only include credentials for same-origin requests.
I read somewhere that Chrome wasn't friendly with cookies and localhost env, maybe it could be that.
https://bugs.chromium.org/p/chromium/issues/detail?id=56211
Furthermore, I had some problems with cookies, express and vueJS some times ago.
Maybe it can help you: SetCookie header not stored
I had read somewhere that you should add a specific domain value to the cookie when creating it. If I just removed that setting, it sets it automatically I'm guessing, and then it worked! So my guess is that I had set the domain value to the wrong value for what I was trying to do
I am having a weird problem where when I make a fetch request from the client in development it is not sending the cookies to my server (legacy server that does not run on localhost).
Here is my code for the fetch request:
get( url ) {
return fetch(`${API_URL}${url}`, {
method: 'GET',
headers: headers(),
credentials: 'include'
}).then( parseResponse );
},
Headers is a function that returns the following object:
{
'Accept': 'application/json',
'Content-Type': 'application/json',
'mobile': 'false'
}
Here are the CORS headers I have set on the server (Access-Control-Allow-Origin is dynamic because fetch has issues with *)
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: mobile, Content-Type
Access-Control-Allow-Origin: http://localhost:3000
If I print out $_COOKIE I get back an empty array and when I look at the request I get Provisional headers are shown with no cookies.
Any ideas where I messed up?
Thanks In Advance :-)
I'm trying to use fetch api.
First i create a new Headers() object:
var oHeaders = new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json',
"X-DocuSign-Authentication": '{"Username":"xxx","Password":"xxx","IntegratorKey":"xxx"}'
})
After headers is instantiated if i try to log headers everything is correct.
oHeaders.forEach(function(v){console.log(v)})
//logs: 2 application/json {"Username":"xxx","Password":"xxx","IntegratorKey":"xxx"}
the i create the Request object:
var oReq = new Request('https://eu.docusign.net/restapi/v2/login_information', {
method: 'GET',
headers: oHeaders,
mode: 'no-cors',
});
If i try to log the headers of the request object only the accept header will be there.
oReq.headers.forEach(function(v){console.log(v)})
//logs: application/json
If i try to fetch(oReq) i get 401 unauthorized response.
What makes the headers disappear?
When you set mode: 'no-cors'for a request, browsers won’t allow you to set any request headers other than CORS-safelisted request-headers. See the spec requirements:
To append a name/value (name/value) pair to a Headers object (headers), run these steps:
Otherwise, if guard is "request-no-cors" and name/value is not a CORS-safelisted request-header, return.
In that algorithm, return equates to “return without adding that header to the Headers object”.