I have a web page served by FastAPI that on a button click is initiating a POST request using pure Javascript to a route in my API which then should redirect to an external page.
The Javascript:
function submit(url) {
let xhr = new XMLHttpRequest();
xhr.open("POST", url, false);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(); }
In my app FastAPI app, I added the following:
app.add_middleware(
CORSMiddleware,
allow_credentials=True,
allow_origins=['*', 'http://127.0.0.1:8080', 'http://127.0.0.1:8080/OpryW?', 'http://127.0.0.1:8080/OpryW'],
allow_methods=["*"],
allow_headers=["*"],
)
When clicking the button, however, I am still getting a CORS error.
Here are some details about the request:
POST: http://127.0.0.1:8080/OpryW
Request headers:
POST /OpryW HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 19
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
sec-ch-ua-platform: "macOS"
Content-Type: application/json
Accept: */*
Origin: http://127.0.0.1:8080
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:8080/OpryW?
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Response headers:
HTTP/1.1 307 Temporary Redirect
date: Mon, 01 Nov 2021 20:00:10 GMT
server: uvicorn
location: http://www.google.com
access-control-allow-origin: *
access-control-allow-credentials: true
Transfer-Encoding: chunked
Why am I still getting a CORS error?
Thanks
Related
When I login the rest_auth API, I get the data:
{"key":"727ac2daf3f0ad2fa1cd13e0905e9941d721f49b","user":{"username":"111111#gmail.com","first_name":"","last_name":"","email":"111112#gmail.com","last_login":"2021-05-18T16:35:12.982804+08:00"}}
but when I use the key as identification to request data, I get 403 forbidden error:
[General]
Request URL: http://127.0.0.1:8000/api/CNAME/list/
Request Method: GET
Status Code: 403 Forbidden
Remote Address: 127.0.0.1:8000
Referrer Policy: strict-origin-when-cross-origin
[Response Headers]
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://127.0.0.1:8080
Allow: GET, HEAD, OPTIONS
Content-Length: 43
Content-Type: application/json
Date: Tue, 18 May 2021 08:35:13 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Accept, Origin, Cookie
X-Frame-Options: SAMEORIGIN
[Request Headers]
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Authorization: Token 727ac2daf3f0ad2fa1cd13e0905e9941d721f49b
Connection: keep-alive
Host: 127.0.0.1:8000
Origin: http://127.0.0.1:8080
Referer: http://127.0.0.1:8080/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
For some reason cookies set by server are not being saved, can't access them from within my js code, in devtools in Application tab in cookies section it's all empty, but somehow when I make a request to the server after the initial one, those cookies that apparently didn't save are being included in the header.
I have set withCredentials to true in axios config, as well as CORS_ALLOW_CREDENTIALS to true on my backend.
Here are the headers from the request that should save cookies:
Response Header:
access-control-allow-credentials: true
access-control-allow-origin: <frontend url>
content-length: 22
content-type: text/html; charset=utf-8
date: Mon, 01 Feb 2021 12:04:09 GMT
server: nginx/1.19.2
set-cookie: csrftoken=<token>; expires=Mon, 31 Jan 2022 12:04:09 GMT; Max-Age=31449600; Path=/; SameSite=Lax
set-cookie: sessionid=<sessionid>; expires=Mon, 01 Feb 2021 13:04:09 GMT; HttpOnly; Max-Age=3600; Path=/
strict-transport-security: max-age=31536000
vary: Cookie, Origin
x-frame-options: SAMEORIGIN
Request Headers:
:authority: <backend url>
:method: POST
:path: /login/
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cache-control: no-cache
content-length: 66
content-type: application/json;charset=UTF-8
dnt: 1
origin: <frontend url>
pragma: no-cache
referer: <current frontend url query>
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
As you can see in the response I'm getting two cookies to be set, sessionid and csrftoken, those are not being saved.
What's weird those cookies are present in the following request:
Request Headers:
:authority: <backend url>
:method: GET
:path: /numbers/
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
cache-control: no-cache
cookie: csrftoken=<token>; sessionid=<sessionid>
dnt: 1
origin: <frontend url>
pragma: no-cache
referer: <current frontend url query>
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
How is it possible for the cookies to not be set but still included in the request? And what can cause this behavior? I really need them to be saved.
My backend and frontend are located at different urls, my backend is running on Django with a rest-framework.
UPDATE
I've also tried to set samesite on the cookies to none, as well as changing request content-type to application/x-www-form-urlencoded. Still no luck.
After hours spent troubleshooting this problem I found out a solution, somewhat. My frontend app and backend app are hosted from different urls, but under the same domain, like that: <frontend>.<mydomain>.com and <backend>.<mydomain>.com
When frontend application was making a request to the backend, backend was sending set-cookie headers that would save the cookies under <backend>.<mydomain>.com (I was able to confirm this in here: chrome://settings/siteData), which made them inaccessible from within <frontend>.<mydomain>.com, I were able to fix that by adding a domain property to the set-cookie header that would point to .<mydomain>.com. To do that I had to create a middleware in Django that would add my predefined domain name to the cookies before being send back to the client.
I'm not really 100% happy with this because if my applications were served from different domains, I'm not sure if I could make the cookies work at all, since setting set-cookie to a different domain is not allowed by the browser.
I'm working with a public API that is poorly configured, i.e. the server doesn't set the Cache-Control header when it should.
Can I use HTTP request headers or alter response headers, so that a response is cached at the browser level for some period of time?
In the context of this API the response will be fresh until a specific data time calculated previously.
I looked quite a bit, but cannot seem to find anything related to setting request headers.
Note, I'm working in javascript and using fetch() to make requests.
Here is the state of the current headers:
Request Headers
:authority: fantasy.premierleague.com
:method: GET
:path: /api/entry/1157414/event/3/picks/
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
sec-ch-ua-mobile: ?0
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Response Headers
accept-ranges: bytes
content-length: 571
content-type: text/html
date: Fri, 25 Dec 2020 16:57:32 GMT
server: nginx/1.18.0
via: 1.1 google, 1.1 varnish, 1.1 varnish
x-cache: MISS, MISS
x-cache-hits: 0, 0
x-served-by: cache-lhr7366-LHR, cache-fra19130-FRA
x-timer: S1608915452.118518,VS0,VE22
The following code is used to connect to an API and get data.
function req() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://url/api");
xhr.setRequestHeader("Accept", "*");
xhr.setRequestHeader("uid", "1234");
xhr.setRequestHeader("x-api-key", "1234");
xhr.send();
}
The function is called via a button
The API is confirmed working with postman. Firefox displays the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
The interesting problem is that when inspecting with Firefox, the set headers seem to be misaligned
Host: url
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: uid,x-api-key
Origin: null
Connection: keep-alive
I can edit this in Firefox to the correct way:
Host: url
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
uid: 1234
x-api-key: 1234
Origin: null
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
And will get successful state 200
What could be the issue of wrong formatting when using js?
I am trying to add a completely custom HTTP header - in this case as an example - Header=dog with value=cat. When I run this, in stead of getting a new header, it appends dog to the values in access-control-request-headers? How do I get a new custom header?
Code:
HR = new XMLHttpRequest();
HR.onload = function (e) {
}
HR.open("GET", URI);
HR.setRequestHeader('dog', 'cat');
HR.send();
Request headers as viewed through Chrome developer tools:
access-control-request-headers: origin, dog
access-control-request-method: GET
origin: http://localhost:8888
accept-encoding: gzip,deflate,sdch
accept-language: en-US,en;q=0.8
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
:path: /
accept: */*
:version: HTTP/1.1
cache-control: max-age=0
referer: http://localhost:8888/x.html
:scheme: https
:method: OPTIONS
Response Headersview source
access-control-allow-headers:origin, dog
access-control-allow-methods:OPTIONS
access-control-allow-origin:*
access-control-max-age:300
cache-control:private, no-cache, no-store, must-revalidate
content-length:0