Django Rest Framework CORS blocking XMLHttpRequest - javascript

I have set up my CORS policy using Django-cors-headers with the following settings:
APPEND_SLASH=False
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'localhost:3000',
'localhost'
)
I have also added it to installed_apps and middleware.
Now I am making a React app for the front end and using AXIOS for my API requests. When I make an API request to log in to my app the CORS policy allows it. But, if I make an API request that requires a Token, I get:
Access to XMLHttpRequest at 'localhost:8000/api/TestConnection/' from origin 'http://localhost:3000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
It seems that I need to allow XMLHttpRequest for supported protocol schemes but I cannot find anything in the pypi documentation about this.
EDIT:
Here is the AXIOS Request:
axios.post("localhost:8000/api/TestConnection/",
{headers:
{
'Authorization': "Bearer " + localStorage.getItem('JWTAccess')
}
},
{
testString: 'Hello API'
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error);
})
Thank you!

I Have had a similar issue with a ReactNative app which was happening due to ReactNative using IP 10.0.2.2 for localhost (I do not remember the details or why). I solved it by adding to my class.
componentWillMount() {
axios.defaults.baseURL = 'http://10.0.2.2:8000/api/';
axios.defaults.timeout = 1500;
}
I do not know if this is the right IP but may be worth looking at.
EDIT
handleRequest() {
const payload = { username: this.state.username, password: this.state.password }
axios
.post('login/', payload)
.then(response => {
const { token, user } = response.data;
// We set the returned token as the default authorization header
axios.defaults.headers.common.Authorization = `Token ${token}`;
// Navigate to the home screen
Actions.main();
})
.catch(error => {
console.log(error)
});
}
By saving the Token within my headers it is always sent.

The error says "from origin 'http://localhost:3000'" and to "check the cors policy"
I see your CORS policy is
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'localhost:3000',
'localhost'
)
maybe try providing the full http url. so
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'http://localhost:3000',
'localhost'
)

I solved it! The solution was very simple(of course),
For the request I needed to use part of #HenryM 's solution.
First I needed to establish the default url:
axios.defaults.baseURL = 'http://127.0.0.1:8000/api/';
Then I save the payload and header to const variables:
const header = {
headers:{
'Authorization': "Bearer " + localStorage.getItem('JWTAccess')
}
}
const payload = {
testValue: "Hello API"
}
Finally, the main issue was that my parameters were in the wrong order:
axios.post("TestConnection/", payload, header)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error);
Apparently the propper order, at least when using Django Rest Framework, is payload then header!!!
Thank you to everyone who tired to help!
This was the article that ended up helping me: https://www.techiediaries.com/django-vuejs-api-views/

Related

CORS Policy Error when attempting to POST to Twilio API

From a VueJS application I'm attempting to do a simple POST to the Twilio API in order to send an SMS. When the POST is executed I receive the following error:
"Access to XMLHttpRequest at 'https://api.twilio.com/2010-04-01/Accounts/AC42exxxxxxxxxxcfa9c48/SMS/Messages' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field username is not allowed by Access-Control-Allow-Headers in preflight response."
The offending code is the following:
sendTwilio(){
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const sFromNumber = process.env.TWILIO_NUMBER;
const sBaseURL = 'https://api.twilio.com';
const phoneNumber = parsePhoneNumberFromString(this.sms.to_number,'US')
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`,
'username': `${accountSid}`
},
sBodyText='Test'
this.SmsUrl = sBaseURL + '/2010-04-01/Accounts/' + accountSid + '/SMS/Messages';
if (phoneNumber.isValid()){
this.sms.formattedPhone = phoneNumber.number;
this.postData = 'From=' + sFromNumber
+ '+To=' + phoneNumber.number
+ '+Body=' + sBodyText
axios.post(`${this.SmsUrl}`, this.postData, {
headers: headers
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
},
Is the problem with the format used for the username in the header or something with my CORS settings?
My CORS settings are as follows:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:8000',
'http://localhost:8080',
'http://127.0.0.1:8000'
]
Twilio uses Basic Auth to do authentication, so in your case when doing your POST using axios you need to do:
const headers = {
'Content-Type': 'application/json'
};
const auth = {
username: accountSid,
password: authToken
}
[...]
axios.post(this.SmsUrl, this.postData, {
auth: auth,
headers: headers
})
I'm not sure how you're using this though. Have a look at the comments of the question. You should never expose your Twilio credentials to the client in a browser application.

How to hook up github oauth 2.0 with http in javascript

Good day,
I am trying on github oauth2.0 apis and got stuck on calling /access_token with fetch and axios.
I have successfully gotten /authorize api to work and have client_id, client_secret, and code passed successfully to getAccessToken function. However, failed at making the fetch with cors error issue returned.
Things that I had explored
https://www.sohamkamani.com/blog/javascript/2018-06-24-oauth-with-node-js/
https://github.com/sohamkamani/node-oauth-example
https://github.com/evert/fetch-mw-oauth2
Code:
export const authorize = async () => {
const uri = withQuery('https://github.com/login/oauth/authorize', {
client_id: process.env.VUE_APP_CLIENT_ID,
redirect_uri: 'http://localhost:8080/authorize',
scope: 'read:user',
});
window.location.replace(uri);
};
export const getAccessToken = async (code: string) => {
const { VUE_APP_CLIENT_ID, VUE_APP_CLIENT_SECRET } = process.env;
const uri = withQuery('https://github.com/login/oauth/access_token', {
client_id: VUE_APP_CLIENT_ID,
client_secret: VUE_APP_CLIENT_SECRET,
code,
});
axios({
method: 'post',
url: uri,
headers: {
accept: 'application/json',
},
}).then(response => {
console.log('response: ', response);
});
};
Axios error:
authorize:1 Access to XMLHttpRequest at 'https://github.com/login/oauth/access_token?client_id=abcdefgh&client_secret=abcdefgh' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
createError.js?2d83:16 Uncaught (in promise) Error: Network Error
at createError (createError.js?2d83:16)
at XMLHttpRequest.handleError (xhr.js?b50d:81)
Because of some security-related limitations, Github prevents developers from implementing the OAuth Web Application Flow on a client-side only application.
References:
https://github.com/isaacs/github/issues/330
Working Solution:
https://github.com/prose/gatekeeper

Angular 6 Http request fails with authorization headers

I'm deploying and angular 6 application that works with a tomcat server in localhost, when I try to execure this http request
this.http
.post<LoginResult>( API_URL + '/login', JSON.stringify(json)/*, { headers: myHeader }*/).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
everitying works well, but when I add header field
let myHeader = new HttpHeaders().append("Authorization", 'Basic' + this.session.getAccessToken());
this.http
.post<LoginResult>( API_URL + '/login', JSON.stringify(json), { headers: myHeader }).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
this is my output error:
Access to XMLHttpRequest at 'http://localhost:8095/login' 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.
HttpErrorResponse
I checked also that the request doesn't arrive to my tomcat server, it is blocked before, that oesn't allow angular to check response headers
Thank you for your help
I'm providing you a generic answer as you have not mention that your server side code is written in which language. You should provide a header from your server code. Provide Access-Control-Allow-Origin header with value as localhost:4200 which will resolve your issue. Or if you want to allow every origin then change its value from localhost:4200 to *.
After reading all the comments I have change something for you.
change your this code let myHeader = new HttpHeaders().append("Authorization", 'Basic' + this.session.getAccessToken()); with const myHeader = new HttpHeaders({'Authorization': 'Bearer ' + localStorage.getItem('api_token')});
and make your post request as
this.http
.post<LoginResult>( API_URL + '/login', json, myHeader).pipe(
catchError(this.handleError('get-token', []))).subscribe((response) => {
if(response['result_code'] == 'result_ok') {
this.auth.doSignIn(response['token'], response['name']);
this.router.navigate(['user_manager']);
return true;
}else {
return false;
}
});
You need to configure CORS on your tomcat server.
You need to tell tomcat which headers the application is allowed to send, so it can include it in the preflight response:
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Authorization,Content-Type,...</param-value>
</init-param>
Take a look at
cors.allowed.methods under CORS Filter section here:
https://tomcat.apache.org/tomcat-7.0-doc/config/filter.html

ElectronJS Vue Axios Basic Authentication Access-Control-Allow-Origin error

I have been googling the all of the interwebs and I just can't find the solution to my problem. I'm trying to make an application using ElectronJS and I need to send an HTTP request with authentication basic header but I just can't get it to work.
Here's my code:
export default {
name: 'home',
data: function() {
return {token: ''}
},
methods: {
fetchData() {
this.$http({
method: 'get',
url: 'URL_TO_SERVER',
auth: {
username: 'USERNAME',
password: 'PASSWORD'
},
headers: {
'Access-Control-Allow-Origin': '*',
credentials: 'same-origin',
},
withCredentials: true,
}).then((response) => {
console.log(response.data);
}).catch((error) => {
console.log('ERROR: '+ error.response.data);
});
}
}
}
I am getting the following error:
XMLHttpRequest cannot load (URL_TO_SERVER). 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:9080' is therefore not allowed access. The response had HTTP status code 401.
Does anyone have any idea's what could be my next step to fixing this?
If i do the same info with a REST client it will return the correct values, just not in ElectronJS
After building the application in to an EXE, it worked, just doesnt work in npm run dev.

Error: The Content-Range header is missing in the HTTP Response

I am setting up admin on rest, and now I am getting this error when I try to fetch data, even though I receive all the data needed from the server:
The Content-Range header is missing in the HTTP Response. The simple REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?
Is there a way to solve it without making changes to the API? I was doing authorization based on the tutorial, here is my app.js:
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const token = localStorage.getItem('token');
options.headers.set('Authorization', `Bearer ${"token"}`);
return fetchUtils.fetchJson(url, options);
}
const restClient = simpleRestClient('https://mywebsite.com', httpClient);
const App = () => (
<Admin restClient={restClient} authClient={authClient}>
<Resource name="posts" list={PostList} edit={PostEdit} create={PostCreate}/>
<Resource name="users" list={UserList}/>
</Admin>
);
The issue is not on the React-App but rather your REST server.
In my case, I was using the SimpleRestClient and in their documentation it reads
import simpleRestProvider from 'ra-data-simple-rest';
Note: The simple REST client expects the API to include a
Content-Range header in the response to GET_LIST calls. The value must
be the total number of resources in the collection. This allows
admin-on-rest to know how many pages of resources there are in total,
and build the pagination controls.
Content-Range: posts 0-24/319 If your API is on another domain as the
JS code, you’ll need to whitelist this header with an
Access-Control-Expose-Headers CORS header.
Access-Control-Expose-Headers: Content-Range
So, from your server/the REST server it has to return(include in response) two headers
Access-Control-Expose-Headers: Content-Range
Content-Range: posts 0-24/319
In my flask-server here's what i did
Add the 'content-range' header in your responses.
response.headers.add( 'Access-Control-Expose-Headers', 'Content-Range')
Add the header 'Content-Range' and assign it a range value(usually in bytes)
response.headers.add('Content-Range','bytes : 0-9/*')
Finally: I noticed that when either of the headers is omitted from your response you'd get the same error
Error: The Content-Range header is missing in the HTTP Response
Ensure your server returns these headers
'Access-Control-Expose-Headers', 'Content-Range'
or
'Content-Range','bytes : 0-9/*'
I hope this helps as it's my ever first response to a SO question
If you are using fastapi with react admin you need to add this to route
response.headers['X-Total-Count'] = '30'
response.headers['Access-Control-Expose-Headers'] = 'Content-Range'
``
You need to add custom headers to your requests, you can just wrap the fetchJson() call inside your own function:
For instance:
import { fetchUtils, Admin, Resource } from 'react-admin';
import simpleRestProvider from 'ra-data-simple-rest';
const fetchJson = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
// add your own headers here
options.headers.set('X-Custom-Header', 'foobar');
return fetchUtils.fetchJson(url, options);
}
const dataProvider = simpleRestProvider('http://path.to.my.api/', fetchJson);
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);
For the most common usage of custom headers is for authentication. fetchJson has built-on support for the Authorization token header:
const fetchJson = (url, options = {}) => {
options.user = {
authenticated: true,
token: 'SRTRDFVESGNJYTUKTYTHRG'
};
return fetchUtils.fetchJson(url, options);
};
const dataProvider = simpleRestProvider('http://path.to.my.api/', fetchJson);
Now all the requests to the REST API will contain the Authorization: SRTRDFVESGNJYTUKTYTHRG header.

Categories

Resources