Postman request works but not axios CORS - javascript

In a bit of a pickle at the moment , I could do a postman request like that and I get my data response back :
URL : https://hiddenurlforexample.com
Authorization : Bearer XXXXXXXX-XXXX-XXXX-XXXX
When I do it on Axios on my website though I get a 401 CORS error. Any idea what the difference is ? This is how my axios request looks like :
axios
.request({
url: 'test/url',
method: 'get',
baseURL: 'https://hiddenurlforexample.com',
headers: {
"Access-Control-Allow-Origin" : "*",
"Content-type": "Application/json",
"Authorization": "Bearer XXXXXXXX-XXXX-XXXX-XXXX"
}
})
.then(response => {
console.log(response.data)
})
.catch(function (error) {
console.log(error)
})
I am a Frontend Developer, I have been told that there was nothing to do in the backend .

What Chris G said, and next to that Postman ignores the CORS validation because it is a dev tool.
Your backend server should return the correct CORS headers. While developing you could go with a wildcard for the CORS headers but it's highly recommended to add the specific domain you're calling the backend from (i.e. the domain of your website).
Also note that the CORS headers are returned via an OPTIONS call, again, your backend should support that. What backend are you running?

Related

CORS error using fetch API - React create app

I'm consuming an API using fetch but i'm getting CORS error.
I tried multiples headers, but I'm not understading what's the problem.
I'm not the owner of the API, so I couldn't change it, but checking the response it's returning access-control-allow-origin.
Following is my request method:
export const execPOST = (url, body) => {
return fetch(url, {
method: "POST",
headers: {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json"
},
body: JSON.stringify(body)
});
};
The response is:
Request URL: http://api
Request Method: OPTIONS
Status Code: 405 Method Not Allowed
Remote Address: ip
Referrer Policy: no-referrer-when-downgrade
Response Headers:
Access-Control-Allow-Origin: *
Isn't this response above enough to allow my request?
console error:
OPTIONS http://api net::ERR_ABORTED 405 (Method Not Allowed)
Access to fetch at 'http://api' 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.
I got this working (meanwhile I develop) using "https://cors-anywhere.herokuapp.com/", but I don't think that I should use this for production enviroment.
I found a lot of material about this problem, but nothing that worked besides implements a backend to make the request or use something else as a proxy to make the request and so on...
Update code as given below (use 'mode' with the value 'no-cors' ):
For more details follow the link => https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
export const execPOST = (url: string, body: any) => {
return fetch(url, {
mode: 'no-cors',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
});
};
CORS headers are set by the API to protect users from malicious code making requests to sites on their behalf.
This means that you cannot enable or disable it from the client side as the Access-Control-Allow-Origin header is a server side only header.
If you don't have access to the API to change the headers then you won't be able to use the API from the client side.
In production you would have to create your own API that will handle the requests to the API you are trying to contact.

POST working with Postman but not via fetch in JavaScript

The post request to the Django Rest API framework works via Postman when the appropriate parameters are filled in the 'body' section. But the same does not work with the following JavaScript code:
var data = {emp_id:50,emp_name:'test',password:'pass123'};
fetch('http://127.0.0.1:8000/signup/',{
method:"POST",
body: JSON.stringify(data),
mode:"no-cors",
headers: {
"Content-Type": "application/json",
// "Content-Type": "application/x-www-form-urlencoded",
},
})
.then(response => response.json());
The following is the def that handles the POST request in the views.py of the REST-API:
#api_view(['GET', 'POST', ])
def signup(request):
serializer = employeeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I'm new to this, can anyone tell me why the JavaScript code won't work?
EDIT:
The error which the browser console shows is:
POST http://127.0.0.1:8000/signup/ 415 (Unsupported Media Type)
The issue is that by using no-cors mode you constrain yourself to using simple requests, which in turn cannot have content-type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain. In fact, if you look at the headers sent by the browser with your request, you'll see that the content type changes from application/json to text/plain - hence the error.
To fix your issue: remove no-cors mode and add cors headers to responses in your django app. You can use django-cors-headers for that.
Also, you have no issues with postman because it does not care about same-origin policy.
Try change headers to
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
The accept header is used by to determine what format to sent the data back to the client in the response, guess it might be needed
I found the solution here : https://learning.postman.com/docs/sending-requests/generate-code-snippets/#generating-code-snippets-in-postman
with postman you can see the code of headers sent on the request on many languages (Node Axios, javascript fetch ...), then just copy paste the headers and all the data sent by postman to your app

Unable to make LinkedIn API calls from localhost with Axios

I am trying to access linkedin profile using axios get request, which doesn't work on localhost and I get the following error
XMLHttpRequest cannot load
https://api.linkedin.com/v1/people/~:(id,email-address)?format=json.
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:8030' is therefore not allowed
access. The response had HTTP status code 401.
I am able to get access-token using react-linkedin-login package, after getting the access token I am trying the following code
var linkedInUrl = `https://api.linkedin.com/v1/people/~:(id,email-address)?format=json`;
var headers = {
'Authorization': `Bearer ${accessToken}`,
'Access-Control-Allow-Methods':'GET,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin':'*',
'Access-Control-Request-Headers':'Origin, X-Requested-With, Content-Type, Accept',
'Content-Type':'application/x-www-form-urlencoded'
};
return (dispatch) => {
axios.get(linkedInUrl, {headers}).then(({data}) => {
console.log(data);
}, (error) => {
console.log(error);
});
}
The problems lies in linkedin server how it takes request I guess, it doesn't allow localhost to make call I think. How to overcome this to actually develop the service before I deploy and run on server.
Thanks for helping..
This is because of a browser restriction called the "Same-origin Policy", which prevents fetching data from, or posting data to, URLs that are part of other domains. You can get around it if the other domain supports Cross-origin Resource Sharing (CORS), but it looks like LinkedIn doesn't, so you may have trouble.
One way around this is to have a web service which can proxy your request to LinkedIn - there's no domain restrictions there.
https://en.wikipedia.org/wiki/Same-origin_policy
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
try jsonp for CORS request - reference - axios cookbook
var jsonp = require('jsonp');
jsonp(linkedInUrl, null, function (err, data) {
if (err) {
console.error(err.message);
} else {
console.log(data);
}
});
EDIT
Use jQuery to perform JSONP request and to set headers
$.ajax({url: linkedInUrl,
type: 'GET',
contentType: "application/json",
headers: header, /* pass your header object */
dataType: 'jsonp',
success: function(data) {
console.log(data);
},
error: function(err) {
console.log('Error', err);
},
});
https://cors-anywhere.herokuapp.com/ - Add this before the url and it will work

Why is Fetch API call not returning the response headers?

I'm building a SignUp form and have the following API call to POST the form:
const request = new Request('http://localhost:4300/auth/', {
method: 'POST',
headers: new Headers({
'Accept' : 'application/json',
'Content-Type' : 'application/json',
}),
body: JSON.stringify({ user: data })
});
fetch(request).then(response => {
console.log(response);
const auth = response.headers.get('Authorization');
console.log(auth)
});
The problem is response.headers.get('Authorization') is returning as null. Even though if I look at Chrome's Network XHR request I see the Response Headers being sent by the API server.
Why is React not providing me with response.headers via the request above?
Thanks
The value of the Access-Control-Expose-Headers response header for the response from http://localhost:4300/auth/ must include "Authorization" if you want your requesting frontend JavaScript code to be allowed to access the Authorization response header value.
If the response includes no value for the Access-Control-Expose-Headers header, the only response headers browsers will let you access from client-side JavaScript in your web app are Cache-Control,
Content-Language,
Content-Type,
Expires,
Last-Modified
and
Pragma.
See https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name for the spec.

How to send authorization header with axios

How can I send an authentication header with a token via axios.js?
I have tried a few things without success, for example:
const header = `Authorization: Bearer ${token}`;
return axios.get(URLConstants.USER_URL, { headers: { header } });
Gives me this error:
XMLHttpRequest cannot load http://localhost:8000/accounts/user/. Request header field header is not allowed by Access-Control-Allow-Headers in preflight response.
I have managed to get it work by setting global default, but I'm guessing this is not the best idea for a single request:
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
Update :
Cole's answer helped me find the problem. I am using django-cors-headers middleware which already handles authorization header by default.
But I was able to understand the error message and fixed an error in my axios request code, which should look like this
return axios.get(URLConstants.USER_URL, { headers: { Authorization: `Bearer ${data.token}` } });
On non-simple http requests your browser will send a "preflight" request (an OPTIONS method request) first in order to determine what the site in question considers safe information to send (see here for the cross-origin policy spec about this). One of the relevant headers that the host can set in a preflight response is Access-Control-Allow-Headers. If any of the headers you want to send were not listed in either the spec's list of whitelisted headers or the server's preflight response, then the browser will refuse to send your request.
In your case, you're trying to send an Authorization header, which is not considered one of the universally safe to send headers. The browser then sends a preflight request to ask the server whether it should send that header. The server is either sending an empty Access-Control-Allow-Headers header (which is considered to mean "don't allow any extra headers") or it's sending a header which doesn't include Authorization in its list of allowed headers. Because of this, the browser is not going to send your request and instead chooses to notify you by throwing an error.
Any Javascript workaround you find that lets you send this request anyways should be considered a bug as it is against the cross origin request policy your browser is trying to enforce for your own safety.
tl;dr - If you'd like to send Authorization headers, your server had better be configured to allow it. Set your server up so it responds to an OPTIONS request at that url with an Access-Control-Allow-Headers: Authorization header.
This has worked for me:
let webApiUrl = 'example.com/getStuff';
let tokenStr = 'xxyyzz';
axios.get(webApiUrl, { headers: {"Authorization" : `Bearer ${tokenStr}`} });
Rather than adding it to every request, you can just add it as a default config like so.
axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`
Try this :
axios.get(
url,
{headers: {
"name" : "value"
}
}
)
.then((response) => {
var response = response.data;
},
(error) => {
var status = error.response.status
}
);
You are nearly correct, just adjust your code this way
const headers = { Authorization: `Bearer ${token}` };
return axios.get(URLConstants.USER_URL, { headers });
notice where I place the backticks, I added ' ' after Bearer, you can omit if you'll be sure to handle at the server-side
Instead of calling axios.get function Use:
axios({ method: 'get', url: 'your URL', headers: { Authorization: `Bearer ${token}` } })
const response=await axios(url,
method:"GET"
{
headers: {
"Authorization" : `Bearer ${token}`
}
})
You can try this.
axios.get(
url,
{headers: {
"Access-Control-Allow-Origin" : "*",
"Content-type": "Application/json",
"Authorization": `Bearer ${your-token}`
}
}
)
.then((response) => {
var response = response.data;
},
(error) => {
var status = error.response.status
}
);
create a new axios instace for your request
const instance=axios.create({
baseURL:'www.google.com/'
headers:{
'Content-Type':'application/json',
'Acess-Control-Allow-Origin':'*',
'Authorization':`Bearer ${token}`,
'Accept': "application/json"
}
})
await instance.get(url,data)
Install the cors middleware. We were trying to solve it with our own code, but all attempts failed miserably.
This made it work:
cors = require('cors')
app.use(cors());
Original link
This is the Postman way of doing it:
headers: {
'Authorization': `Basic ${Buffer.from('username:password').toString('base64')}`
}
res.setHeader('Access-Control-Allow-Headers',
'Access-Control-Allow-Headers, Origin,OPTIONS,Accept,Authorization, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
Blockquote
: you have to add OPTIONS & Authorization to the setHeader()
this change has fixed my problem, just give a try!

Categories