cookies are not being sent during post request (flask-cors) - flask

i have credentials in cookies that must be sent over a post request, but they are not present.
however, they are present in get requests
here is my flask cors config
CORS(
app,
resources={"/*": {"origins": ["http://localhost:3000", "http://localhost:1002"]}},
allow_headers="*",
supports_credentials=True,
expose_headers=[
"tokens",
"Set-Cookie",
"Access-Control-Allow-Origin",
"Access-Control-Allow-Credentials",
],
)
here is the response from preflight (options)
As you can tell I have allow credentials true, and my allow-origin is explicitly set to an origin
again, all get requests succeed, while all post requests fail with a 401 where the cookies are nowhere to be found.

Related

My cookies are not being sent over preflight request during a POST request (flask-cors)

I have a Resource that will need credentials
I have set up my flask-cors like so
CORS(
app,
resources={"/*": {"origins": ["http://localhost:3000", "http://localhost:1002"]}},
allow_headers="*",
supports_credentials=True,
)
config variables
CORS_EXPOSE_HEADERS = ["tokens", "Set-Cookie", "Access-Control-Allow-Origin"]
CORS_SUPPORTS_CREDENTIALS = True
here is the network details of my preflight request
I want the header 'tokens' to be sent to my post request, but it isn't.
all get requests works.

CSRF Verification fails in production for Cross Domain POST request

The HTTP_X_CSRFTOKEN header does not match what is inside the csrftoken cookie.
How can I examine the cookie? Set-Cookie is not displayed in the Response header for Cross Domain requests.
I have already followed instructions found in:
CSRF with Django, React+Redux using Axios
Interestingly I found "X-CSRFTOKEN" translates to "HTTP_X_CSRFTOKEN" on the server request header.
Works fine in the development env under localhost (although I am using 2 different ports - one for django and the other my frontend).
UPDATE:
It seems the csrktoken cookie is not correctly set for cross domain rquests (although the browser displays it in the Request Header) so the X-CSRFTOKEN does not get sent.
I ended up adding an API call to return the current csrftoken using a GET request and then sending it back using the X-CSRFTOKEN header.
You haven't mentioned how you're getting the csrftoken from the server in the first place, so I'm assuming it's already present in your browser.
Along with the X-CSRFToken header, also include the cookies in the request using withCredentials: true.
I'm using the js-cookie library to get the csrftoken from the cookies.
import Cookies from 'js-cookie';
axios({
url: 'http://localhost:8000/graphql',
method: 'post',
withCredentials: true,
data: {
query: `
{
// Your query here
}
`
},
headers: {
"X-CSRFToken": Cookies.get('csrftoken')
}
})
Also add CORS_ALLOW_CREDENTIALS = True to your settings.py, assuming you are using django-cors-headers. Otherwise, the cookies won't be accepted.
You will have to make the X-CSRFTOKEN header accessible via the CORS Access-Control-Expose-Headers directive. Example:
Access-Control-Expose-Headers: X-CSRFTOKEN
This header has to be set by your API or web server, so that the browser will see it during the CORS preflight request.

Vue.js frontend interacting with Flask backend CORS issues due to not allowed preflight headers

I am stuck with the following error message in the Chrome browser:
Failed to load http://localhost:5000/my_endpoint: Request header field
Access-Control-Allow-Origin is not allowed by
Access-Control-Allow-Headers in preflight response.
The browser is loading a webpage from a Vue.js frontend app with webpack etc. and vue-resource to perform HTTP requests to the REST backend.
The URL http://localhost:5000/my_endpoint is a HTTP GET/POST endpoint served by a python Flask application.
On the frontend Javascript I have these CORS settings:
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.http.options.crossOrigin = true
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'
On the backend python code in the Flask app I have the following CORS configuration details:
#app.after_request
def add_header(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'Access-Control-Allow-Headers, Origin, X-Requested-With, Content-Type, Accept, Authorization'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS, HEAD'
response.headers['Access-Control-Expose-Headers'] = '*'
return response
When performing this HTTP POST request in the Javascript frontend:
this.$http.post("http://localhost:5000/my_endpoint", { my_custom_key: "my custom value"})//, {emulateJSON: true})
.then((response) => {
// do stuff
})
where { my_custom_key: "my custom value"} is the JSON body of the HTTP POST request, then in the Flask backend for some reason I see an HTTP OPTIONS request coming, cf. the Flask log:
127.0.0.1 - - [26/Jun/2018 21:45:53] "OPTIONS /ad HTTP/1.1" 200 -
There must be some sort of back/forth ceremony to honor before being able to retrieve the JSON data from the backend, but I am lost in these details.
On the internet I've seen all sorts of explanations, and I've been playing a bit with the vue-resource configuration details like:
adding/removing {emulateJSON: true} to the HTTP POST request
adding/removing Vue.http.options.xhr = { withCredentials : true }; to the configuration of Vue.js
but I am not able retrieve the JSON data coming from the backend.
Searching for "CORS" on the Vue.js documentation or on https://github.com/pagekit/vue-resource does not give any information on how to fix these issues with Cross-origin resource sharing (CORS).
How do I get a Vue.js frontend working with a Flask backend on these CORS issues?
The solution was to remove from the frontend: Vue.http.headers.common['Access-Control-Allow-Origin'] = '*' (which actually does not make sense as it's an HTTP header that usually goes into the response from the backend).
Also to clean up a bit more the backend I found out that response.headers['Access-Control-Expose-Headers'] = '*' was not needed. Probably the other HTTP headers could be more slim, but for now I keep them as they are.

400 server error if to try to send http Get requests with params and cookies

I'm trying to send https requests with python "requests" lib
payLoad = {'session_id': str(webSessionId), 'Merchant': 'Company'}
resp = requests.get(url, params = payLoad, cookies = cookiesSession, headers = headers)
print resp.url
But I'm getting server error 400. At the same time if to check url from sent request can see following:
https://url/error
Passed parameters are missing.
If to remove cookies following url is returned:
https://url?Merchant=Company&session_id=d1160eda748a5ede015bbe1abe35606138086fc8
But Server returns 403 error(authorization)
Cookies and headers are valid as were successfully used in previous two https request. But here is some strange situation. How can I send "get" request with params and cookies?

why is XMLHttpRequest.withCredentials necessary even for same site Ajax requests

I am trying to implement an authentication service deployed in a different HTTP server from the one serving my login page.
The following diagram depicts my setup:
On step #1 my browser makes an HTTP GET request to fetch the login page. This is provided as the HTTP response in #2. My browser renders the login page and when I click the login button I send an HTTP POST to a different server (on the same localhost). This is done in #3. The authentication server checks the login details and sends a response that sets the cookie in #4.
The ajax POST request in #3 is made using jQuery:
$.post('http://127.0.0.1:8080/auth-server/some/path/',
{username: 'foo', password: 'foo'},
someCallback);
The authentication service's response (assuming authentication was successful) has the following header:
HTTP/1.1 200
Set-Cookie: session-id=v3876gc9jf22krlun57j6ellaq;Version=1
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: origin, content-type, accept, authorization
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 21 Nov 2016 16:17:08 GMT
So the cookie (session-id) is present in the HTTP response in step #4.
Now if the user tries to login again I would like the authentication service to detect that. To test that scenario I press the login button again in order to repeat the post in #3. I would have expected the second request to contain the cookie. However the second time I press the login button, the request header in the post sent out in #3 does not contain the cookie.
What I have discovered is that for the post in #3 to contain the cookie, I have to do it like this:
$.ajax({
type: 'post',
url: 'http://127.0.0.1:8080/auth-server/some/path',
crossDomain: true,
dataType: 'text',
xhrFields: {
withCredentials: true
},
data: {
username : 'foo',
password : 'foo',
},
success: someCallback
});
Why would that be necessary? MDN states that this is only required for cross-site requests. This SO post also uses xhrFields but only in relation to a cross-domain scenario. I understand that my case is not cross-domain as both the page that serves the script is on localhost, and the page to where the ajax request is sent is on the same host. I also understand that cookie domains are not port specific. Moreover, since my cookie did not explicitly specify a domain, then the effective domain is that of the request meaning 127.0.0.1 which is identical the second time I send the POST request (#3). Finally, the HTTP reponse on #4 already includes Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner.
So why did I have to use the xhrFields: {withCredentials: true} to make this work?
What I understand is that setting Access-Control-Allow-Origin: * is simply enabling cross-site requests but that in order for cookies to be sent then the xhrFields: {withCredentials: true} should be used regardless (as explained in MDN section on requests with credentials). Moreover, I understand that the request is indeed cross-site since the port number is important when deciding whether a request is cross-site or not. Whether the domain of a cookie includes ports is irrelevant. Is this understanding correct?
update
I think this is explained very clearly in this answer, so maybe this question should be deleted.
All parts of the origin must match the host(ajax target) for it to be considered same-origin. The 3 part of the origin https://sales.company.com:9443 for example includes:
protocol/scheme (https - won't match http)
hostname (sales.company.com - won't match subdomain.sales.company.com)
port (9443 - won't match 443)
see https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy