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!
Related
I habe a client written in Javascript (react) which runs on localhost:3000
Here I have a button that sends the credentials to my backend written in python and using flask. The endpoint is running on localhost:5000/login.
My frontend code looks like this:
loginToDatabase = async () => {
console.log("login to database. user: " + this.state.user+" pw: "+this.state.password);
const response = await fetch("http://localhost:5000/login",{
method: 'POST',
body: {
"user": this.state.user,
"password": this.state.password
},
headers: {
"Content-Type": "application/json"
}
});
console.log("response: "+response)
};
My backend code looks like this:
#app.route("/login", methods=['POST'])
def login():
jsonRequest = request.get_json()
receivedUser = jsonRequest.get('user')
receivedPassword = jsonRequest.get('password')
isConnected = opendatabase.openDatabase('localhost',receivedUser,receivedPassword)
if(isConnected == True):
body = json.dumps({
"connection":isConnected,
})
jsonResponse = Response(
body,
mimetype="application/json",
headers={
"Access-Control-Allow-Origin" : "*",
}
)
return (jsonResponse)
else:
body = isConnected
jsonResponse = Response(
body,
headers={
"Access-Control-Allow-Origin" : "*",
)
return (jsonResponse, 401)
Testing the API with Postman works as expected. However using the frontend I receive this error:
Access to fetch at 'http://localhost:5000/login' 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.
After doing some research I figured out why this happens and that I need the header
"Access-Control-Allow-Origin" : "*"
which I included. But still could not make it work.
I then read here https://developer.mozilla.org/de/docs/Web/HTTP/CORS that does not work with application/json.
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded,
multipart/form-data,
text/plain
However I also read here Can't send a post request when the 'Content-Type' is set to 'application/json' that I can set a header
->header('Access-Control-Allow-Headers', 'Content-Type');
which I also tried like this:
if(isConnected == True):
body = json.dumps({
"connection":isConnected,
})
jsonResponse = Response(
body,
mimetype="application/json",
headers={
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Headers": "Content-Type",
}
)
return (jsonResponse)
else:
body = isConnected
jsonResponse = Response(
body,
headers={
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Headers": "Content-Type"
}
)
return (jsonResponse, 401)
But that does also not work.
There are also many more posts about this topic but so far I could not find a solution. I am also new to APIs and webdevelopment.
And also I think my shown login process is far from perfect. It is really just about getting the REST call to work.
Is there a way to solve this and still using JSON? Surely I could use someting like text/plain but that would not be satisfying.
Also (maybe related) if I use text/plain in the frontend I don't receive the error, but in the backend I don't know how the receive the data send via POST. As you can see in the attached picture, I seem to get an empty object?
Where is my mistake and what is the best way to solve this issue with JSON?
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.
I have to implement an angular application with CURD operations. API is already hosted IN AWS, Which is working fine with Postman.
But my angular application getting
Access to XMLHttpRequest at 'https://acp56df5alc.execute-api.us-east-1.amazonaws.com/ams/getmember' from origin 'http://localhost:4200' 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.
My code is like below,
http_GET(actionUrl: string): Observable<any> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
'key': 'x-api-key',
'value': 'NNctr6Tjrw9794gFXf3fi6zWBZ78j6Gv3UCb3y0x',
})
};
return this.http.get<any>(this.baseUrl + actionUrl, httpOptions).pipe(
(response => {
return response;
}));
}
I have tried hard to solve this.But need some help
I had the same cors issue and tried all the suggested ways of setting Access-Control-Allow-Origin * without success.
Later I found two issues:
The data format I sent via POST request was not properly formatted.
The server could not handle empty parameters received from the post request.
Original request:
return this.http.post(API_URL + 'customer/login',
{email: email, password: password},{ headers: headers}
)
Worked after i wrapped the post data using JSON.stringify()
return this.http.post(API_URL + 'customer/login',
JSON.stringify({email: email, password: password}),{ headers: headers}
)
All/Most of these headers need to be defined on the server-side (whatever hosts the API on AWS)... not client side.
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
'key': 'x-api-key',
'value': 'NNctr6Tjrw9794gFXf3fi6zWBZ78j6Gv3UCb3y0x',
...
The most likely reason that postman works is that it directly sends a GET request. what you are sending is a complex request which is called 'pre-flight' and which causes an 'OPTIONS' request to be sent before the actual GET. this is not allowed by the remote side.
That's a common CORS problem that (if you're using asp .net core on backend) can be solved enabling CORS following this thread
I'm messing around with react and trying to make a put request to an api. I'm trying to send my body as content-type application/json but it keeps sending as text/plain. If I add the header "Content-Type" : "application/json" I just get this as the return.
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
I'm using this api : http://funtranslations.com/api/yoda
Here is my request:
fetch('http://api.funtranslations.com/translate/yoda.json', {
method: 'PUT',
body: JSON.stringify({
text: this.state.input
})
})
.then(res => {
return console.log(res.json());
})
}
Thank you in advance for attempting to help me :)
I think you are sending data in wrong content-type. According to funtranslation web site content-type should be application/x-www-form-url-encoded
fetch('http://api.funtranslations.com/translate/yoda.json', {
method: 'PUT',
headers: {'Content-Type': 'application/x-www-form-url-encoded', 'Accept': 'application/json'},
body:"text=hadi"
})
.then(res => {
return console.log(res.json());
})
This address is clearly explaining CORS issue
For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.
I love this picture to see what is CORS:
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.