Setting authorization in native browser fetch - javascript

I'm coming across an issue where I can't seem to set the headers for a fetch request and I think I'm missing something
var init = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer myKey'
}
};
return fetch(url, init).then(function(response){...
When the request is inspected in the network tab, I'm not seeing the headers get set and instead see
Access-Control-Request-Headers:accept, authorization, content-type
when I would expect to see
Authorization: Bearer myKey
Content-Type: application/json
Accept: application/json
I've also tried using the native Headers() with zero difference.
Am I missing something here?

I was having the same issue and took a bit of investigating this evening. The problem is cross-origin resource sharing / CORS. With Fetch it is the default and it makes things considerably more complex.
Unless Both the origin and destination are the same it is a cross-domain request, and these are only supported if the request is to a destination that supports CORS ( Cross-Origin Resource Sharing ). If it does not then it will not go through. You'll usually see an error like No 'Access-Control-Allow-Origin' header is present on the requested resource
This is why you can not do Authorization headers on non-CORS sites; see #5 and basic headers
https://fetch.spec.whatwg.org/#concept-headers-guard
https://fetch.spec.whatwg.org/#simple-header
FORBIDDEN HEADER NAMES:
https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name
https://fetch.spec.whatwg.org/#forbidden-header-name
And unfortunately, before you try the XMLHttpRequest route, the same applies:
This is the same with XMLHttpRequest:
https://www.w3.org/TR/XMLHttpRequest/#the-open()-method
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
http://arunranga.com/examples/access-control/credentialedRequest.html
Finally, your choices to move forward are:
1. JSONP
2. Write a proxy that is not in the browser
3. Put CORS on the destination server
This article sums it up nicely

Related

CORS error if PUT has credentials 'include' and Content-Type at the same time

I am using JavaScript fetch() with following options:
window.fetch(path, {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
mode: 'cors',
credentials: 'include',
redirect: 'follow',
referrerPolicy: 'no-referrer',
cache: 'no-cache',
body: JSON.stringify(data)
})
but I get error:
Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
and my Access-Control-Allow-Headers has wildcard *.
It works without Credentials
It works fine if I don't add credentials: include and turn OFF auth on API server.
It works without Content-Type
It works fine if I don't add headers: {'Content-Type': 'application/json'}, and keep auth ON on API server. It means it is sent with text/plain;UTF-8 but content is still JSON.
Headers
Headers from my API server:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: *
http://localhost:3000 is where is my front-end app running on.
Hints
If i get this error, devTools in Chrome are not able to show me response headers (Access-Control-Allow-Headers etc.) and request headers shows Provisional headers are shown with only content-type: application/json in it and in General there is not method: PUT (there is not method at all). So it looks like Chrome stopped it before firing.
Server is on different domain (intern web) and is running on http with SameSite: None without Secure but I have disabled security Cookies without SameSite must be secure in Chrome to walkaround it in development mode.
Is there any relationship between credentials, content-type and PUT? Is it possible to send PUT with credentials and application/json? If it is not possible - how should I send data with PUT method? FormData which are allowed content-type for cors are not supported by PUT.
See the MDN documentation for Access-Control-Allow-Headers:
The value * only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information). In requests with credentials, it is treated as the literal header name * without special semantics. Note that the Authorization header can't be wildcarded and always needs to be listed explicitly.
You need to specify the headers you want to allow explicitly.
Changing Access-Control-Allow-Headers from wildcard * to explicit Content-Type did the trick for me.

Access to fetch at <my-google-cloud-function> from origin 'https://www.reddit.com' has been blocked ... CORS

I am working on a Google Chrome extension to block a subset of images from posts in a user's Reddit feed based on some backend computer vision run in Python in Google Cloud Storage. The Python code takes a single argument (the URL of an image in Reddit), which is passed in JavaScript via:
const api_url = https://<my-google-chrome-url>
var curUrl = $(this).attr("src")
fetch(api_url,{
method: 'POST',
body: JSON.stringify(curUrl),
headers: {
'Content-Type': 'application/json'
},
})
.then(data => {console.log(data)})
When the extension's code runs, I get the following in the console:
Access to fetch at 'https://this-is-the-path-to-my-google-cloud-function' from origin 'https://www.reddit.com' 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.
I have tried multiple solutions, enumerated below:
I have followed the instructions here, such that by using Google's gsutil, I am able to confirm the following to be true for the bucket that my function lives in: [{"maxAgeSeconds": 3600, "method": ["GET", "POST"], "origin": ["https://www.reddit.com"], "responseHeader": ["Content-Type"]}]. I have also tried having ["*"] as my origin, to no avail.
I have also tried using in my fetch, mode: no-cors with no success.
Any suggestions or solutions would be greatly appreciated!
For what you mention, the CORS error in this case seems to come from the Cloud Function.
In order to address this, you should configure CORS for the Cloud Function, not Cloud Storage.
CORS consists of the preflight request and the main request. In your function you should check for preflight request by checking if the request's method is OPTION and if so, respond the appropriate headers. Here is a sample:
def cors_enabled_function(request):
# For more information about CORS and CORS preflight requests, see
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# for more information.
# Set CORS headers for the preflight request
if request.method == 'OPTIONS':
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '3600'
}
return ('', 204, headers)
# Set CORS headers for the main request
headers = {
'Access-Control-Allow-Origin': '*'
}
return ('Hello World!', 200, headers)
For more information, you can read the docs

ReactJS: has been blocked by CORS policy: Response to preflight request doesn't pass access control check

i get this fail on chrome:
Access to fetch at 'http://******/places?holiday_type=resort&currency=EUR&checkin=2019-11-01&checkout=2019-11-10&groups[]=1'
from origin 'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.
My Code is:
getPlaces = async () => {
try {
let response = await fetch(`${BASE_URL}/places?holiday_type=resort&currency=EUR&checkin=2019-11-01&checkout=2019-11-10&groups[]=1`,
{
method: 'GET',
headers: new Headers({
'Accept': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
'Access-Control-Request-Method': 'GET, POST, DELETE, PUT, OPTIONS',
'Authorization': 'Basic ' + Base64.encode(apiuser + ':' + apipassword) ,
}),
})
console.log(response)
} catch (error) {
console.log(error)
}
}
External APIs often block requests like this. I would guess that you are using something like an API-Key for your request which includes payment based on your calls. The problem is that every user can read your key when you call the API in your frontend. Thats why the server is block these.
You need to make a server on your own (e.g. with node.js), call your backend API and then "forward" your request the public API with your secret API key.
Server-to-Server requests won't be blocked and your users can't exploit your API key.
You should also make sure to that your backend server doesn't accepts request which is not your frontend if you want to make it public.
CORS works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. This must be configured in the server to allow cross-domain.
You can temporarily solve this issue by a chrome plugin called CORS.
copied from: How to allow CORS in react.js?
Reference: How to overcome the CORS issue in ReactJS?

XMLHttpRequest has been blocked by CORS policy - https://openid-connect-eu.onelogin.com/oidc/token

I am setting up onelogin and I came to this step where I must send one more POST request with the given code from the first GET request (https://developers.onelogin.com/openid-connect/api/authorization-code-grant).
They are saying I must send the POST request to this URL https://.onelogin.com/oidc/token and I am sending the request with Angular 7.
const headers = new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic <base64 encoded ${environment.clientId}:${environment.clientSecret}`
});
const options = {
headers: headers
};
const body = {
grant_type: 'authorization_code',
code: code,
redirect_url: this.getCallbackURL(),
client_id: environment.clientId,
client_secret: environment.clientSecret
};
return this.httpClient.post('https://openid-connect-eu.onelogin.com/oidc/token', body, options).toPromise();
But then I get this error:
Access to XMLHttpRequest at 'https://openid-connect-eu.onelogin.com/oidc/token' from origin 'https://my-site-name.com' 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.
NOTE: replaced with openid-connect-eu as I am in the EU as described in the documentation.
Javascript prevents POST calls to other domains at the browser level unless they are expressly permitted by the service (and OneLogin doesn't permit this, for security reasons)
I'll add that doing this authentication flow via Javascript is not considered secure since anyone could intercept the clientID and Secret from your code.
For javascript apps, I'd recommend using the Implicit OIDC flow, which is documented here:
https://developers.onelogin.com/openid-connect/api/id-token
OneLogin also has sample code for this:
https://github.com/onelogin/onelogin-oidc-node/tree/master/2.%20Implicit%20Flow

CORS error with window.fetch on YouTube resource

I'm using window.fetch to retrieve a YouTube resource with the following URL:
http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=[id]&format=json
Using Fiddler, I see that I am getting the expected reply from YouTube's servers containing JSON data. However, I'm not able to use it as I'm getting a Javascript error.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:60366' is therefore not allowed
access.
I tried enabling CORS on my window.fetch but I read that this will only work if the server allows CORS in its header response. YouTube doesn't have this header field in its reply.
How do I enable my script to accept a response from YouTube using window.fetch? (I'm using Chrome v44.)
window.fetch(
url, {
method: 'GET',
mode: 'cors',
headers: {
'Accept': 'text/plain',
'Content-Type': 'text/plain'
}
})
...
I think you need to use youtube API to be able to make CORS request.
https://developers.google.com/youtube/v3/

Categories