I'm currently working with Ionic to get data from an API. Although it's been working for the last days, I don't know how it stopped working.
I am using #angular/http to make my requests. When not using any headers, my request goes to GET Method, and doesn't work because I need an Authorization token.
But, if I had Headers via:
let headers = new Headers();
headers.append('Authorization', this.bearerToken);
let options = new RequestOptions({ headers: headers });
It doesn't work either. The request goes to OPTIONS Method, and is returning:
Unauthorized header authorization
Is there anything I can do on Ionic to fix this, or should I warn the API developers in order to make them do some changes?
Edit: The API developers are using Symfony and Nelmio CORS Bundle to handle these settings
nelmio_cors:
defaults:
origin_regex: true
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['Content-Type', 'Authorization']
max_age: 3600
paths:
'^/': ~
As #Moshe mentionned, their configuration should contain some Access-Control-Allow-Headers, and they do apparently..
When it comes to HTTP Headers (such as Authorization) the client sends an OPTIONS request in order to check if the headers are accepted by server first. I've had a similar issue with my client-server relationship. You must enable authorization in Access-Control-Allow-Headers in your server.
Example:
header('Access-Control-Allow-Headers: Content-Type, Authorization');
Related
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.
i get this fail on chrome:
Access to fetch at 'http://******/places?holiday_type=resort¤cy=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¤cy=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?
Why does Request and Fetch return different headers?
Are the headers in Response objects always limited using Fetch? Despite it being used on server, various modes used?
Request seems to return a rich set of headers, while Fetch does not.
Other than language mechanic differences (Promise based, Callback, etc..etc..) How do these two differ? Why is one not returning a rich set of headers and the other is?
fileURL used in both examples are cross domain. On a Node/Express server, a call is made to a Google CDN.
Using Request
https://github.com/request/request
request(fileURL, (err, res, body) => {
//headers in res
//are pretty rich
});
Using Fetch
https://github.com/matthew-andrews/isomorphic-fetch
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
const reqConfig = { method: 'POST',
headers: myHeaders,
body: data,
mode: 'cors', //or 'no-cors', or this field blank..
cache: 'default' };
fetch(fileURL, reqConfig).then(res => {
//headers in res
//are not very complete
})
// I don't have access to CORS policies on server so that is not an option..
edit
Even when operating in {mode: 'no-cors'} the headers are not full..
Since you're running in cors mode the server you request from has to white list the headers you can see.
By default when doing CORS requests only these headers are available:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
fetch is probably not what you want for node unless you have a universal app and need the same code to run on both the client and server. fetch was created for the browser so it will -- at least in the browser -- lock down your headers (see my other answer) so if your desire is to have full access to headers then something specfically for node would be best.
Alfresco community edition-5.1.x. when calling external webservice I'm getting error not able to get result
Code:
function updateList(){
Alfresco.util.Ajax.request({
url: "http://test.com/webservice/mgmobile/mgserver.php?wsfunction=course_get_all_courses&wstoken=7f5e0f05f7c54ece7a23f02fe3718464",
method: Alfresco.util.Ajax.GET,
headers: ('Access-Control-Allow-Origin: *'),
headers: ('Access-Control-Request-Headers: *'),
headers: ('Access-Control-Allow-Methods: *'),
requestContentType: Alfresco.util.Ajax.JSON,
successCallback:{
fn: function(res){
appendOptiOnvalues(res)
},
},
failureCallback:{
fn: function(res){
alert("Error");
},
}
});
}
Error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://test.com/webservice/mgmobile/mgserver.php?wsfunction=course_get_all_courses&wstoken=7f5e0f05f7c54ece7a23f02fe3718464. (Reason: missing token 'content-type' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channel).
Please help on this.
It looks like the call is being made to a non-Alfresco server so configuring CORS on Alfresco is not going to help. Instead, check the CORS configuration on the server you are calling and make sure that it is setting "Access-Control-Allow-Headers" to allow the "content-type" header to be specified. That's probably being set by the Alfresco AJAX util library you are using.
I don't know what server you are calling, so I can't provide CORS help specific to that server, but here is some info on enabling CORS for various types of servers.
We came across this today when trying to call an Alfresco Webscript from the Alfresco Share UI and found the issue was in the Alfresco Platform CORS configuration. Our Alfresco.util.Ajax.request included the following headers with the request by default:
localtoken
x-requested-with
These had to be included in our cors.allowed.headers property in alfresco-global.properties otherwise the request would be rejected with an HTTP 403 by ACS.
Example
cors.enabled=true
cors.allowed.origins=http://localhost:8180
cors.allowed.methods=GET,HEAD,POST,PUT,DELETE,OPTIONS
cors.allowed.headers=origin, authorization, x-file-size, x-file-name, content-type, accept, x-file-type, range, localtoken, x-requested-with
cors.support.credentials=true
cors.exposed.headers=Accept-Ranges, Content-Encoding, Content-Length, Content-Range, content-type, localtoken
Notes
Keep in mind alfresco-global.properties is where you configure this when using the ACS all-in-one-platform-docker container provided by Alfresco. If deploying your own WAR in Tomcat or another application server you'll need to follow instructions specific to that system.
I tried to use jQuery Dropzone to upload an image to Imgur or any other domain but that's not working.
This is my dropzone setup:
$("div.dropzone").dropzone
success: -> console.log arguments
paramName: "image"
method: "post"
maxFilesize: 2
url: "https://api.imgur.com/3/upload"
headers:
Authorization: "Client-ID *************"
This doesn't work. It says that return code is 0. The request headers:
Host: api.imgur.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://my.opencubes.io
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,cache-control,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
First as you can see the cient id doesn't appear :(. But the big problem is that the method used is OPTIONS. The response headers:
I have the same problem when I try to upload the file to another domain of mine (the dropzone is located in a subdomain)
In the console I see:
Une demande multi-origines (Cross-Origin Request) a été bloquée : la politique « Same Origin » ne permet pas de consulter la ressource distante située sur https://api.imgur.com/3/upload. Ceci peut être corrigé en déplaçant la ressource sur le même domaine ou en activant CORS.
Which can be translated by
A multi-origin request was blocked: the policy "Same origin" does not allow to see remote resource located in https://api.imgur.com/3/upload. this an be fixed by moving the resource on the samin domain or by enabling CORS.
The OPTIONS request is a normal request: this is used to ask for permissions relative to CORS restrictions. Have a look to this page to understand how CORS work under the hood.
In your case, this is a pure CORS related issue. The OPTIONS request contains this header:
Access-Control-Request-Headers: authorization,cache-control,x-requested-with
Which means: can I use "authorization", "cache-control" and "x-requested-with" headers in my cross-domain AJAX request ?
The response you get is the following:
Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
Which means: you're allowed to use those headers only: "Authorization", "Content-Type", "Accept", and "X-Mashape-Authorization".
As you can see, "cache-control" and "x-requested-with" are not listed in the allowed list, causing the browser to reject the request.
I've come to 2 test code sample which show this behavior:
Example 1 (working)
var data = new FormData();
data.append('image', 'http://placehold.it/300x500');
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.imgur.com/3/upload', true);
xhr.setRequestHeader('Authorization', 'Client-ID xxxxxxxxxx');
xhr.send(data);
Here are the preflight request's headers sent when running this code (as shown by Firefox 30 devtools, and I've removed unrelated headers such as User-Agent, Accept ...):
OPTIONS https://api.imgur.com/3/upload
Host: api.imgur.com
Origin: http://local.host:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Cache-Control: no-cache
And the corresponding response's headers
access-control-allow-origin :"*"
Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS"
Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
Here, we can see that we prompt access to the "authorization" header, and the server is accepting this header, allong with the POST method and any origin URL, so the CORS requirements are satisfied and the request is allowed by the browser.
Example 2 (not working)
var data = new FormData();
data.append('image', 'http://placehold.it/300x500');
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.imgur.com/3/upload', true);
xhr.setRequestHeader('Authorization', 'Client-ID xxxxxxxxxx');
// the only difference with the previous code is this line
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.send(data);
Preflight request's headers:
OPTIONS https://api.imgur.com/3/upload
Host: api.imgur.com
Origin: http://local.host:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,cache-control
Cache-Control: no-cache
Preflight response's headers (which is the same as in example 1):
access-control-allow-origin :"*"
Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS"
Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
Here, the "Access-Control-Request-Headers" header prompt access for "cache-control", which the server does not provide, so the CORS requirements are not satisfied and the request is rejected by the browser.
Here's a JSFiddle referencing different working and not working demos for your problem: http://jsfiddle.net/pomeh/Lfajnebh/. Pay attention to details to understand what's going on, there is few comments but they are here to emphasis trickiest parts of the code.
As a bonus, I've sent a pull request to DropZone's GitHub repository to fix this problem (https://github.com/enyo/dropzone/pull/685) which allows you to remove pref-defined headers by DropZone. Give it a try:
var myDropzone = new Dropzone('.dropzone', {
//...
headers: {
'Authorization': authorizationHeader,
// remove Cache-Control and X-Requested-With
// to be sent along with the request
'Cache-Control': null,
'X-Requested-With': null
}
});
The code above should work with my patched version (https://github.com/pomeh/dropzone/commit/f0063db6e5697888582421865840258dec1ffdc1), whereas the code above should not:
var myDropzone = new Dropzone('.dropzone', {
//...
headers: {
'Authorization': authorizationHeader,
// remove Cache-Control and X-Requested-With
// to be sent along with the request
}
});
You're running into the browser's same-origin security policy. Every browser has one; "origin" basically means "the same site". my JavaScript on example.com can access whatever it likes on example.com, but it's not allowed to read anything from demonstration.com, example.net, or api.example.com. They're from a different origin. Here's a table of what counts as the same origin.
Without it, I could write a web page that steals all your gmail and private Facebook photos. My malicious JavaScript would make web requests to gmail.com and facebook.com, find the links to your emails & photos, load that data too, and then send it off to my own server.
But some services, like APIs, are designed to be accessed by other services. That's where CORS comes in - Cross-Origin Resource Sharing. Web services can use CORS to tell browsers that it's fine to allow access from scripts. If you want to test your code by submitting to your own server, make sure your server is sending the required HTTP response headers.
If you're developing locally, you must also be sure to test from a web server - an address beginning with http://, not file://. The protocol is part of the origin, so you can't submit to an http endpoint from a file URL.
CORS has different types of requests. Some requests are considered simple requests, but others - requests with custom headers - require "preflighting". This means the browser will send a request to the server saying "Is this request OK for CORS?" using the HTTP OPTIONS method before sending the actual request. Any request with custom headers requires preflighting; that's where your HTTP OPTIONS is coming from. jQuery adds a custom X-Requested-With header to AJAX requests, so even if you hadn't added those you'd still see that Options request before the actual POST.
From your screenshots, it looks like Imgur is going to allow your HTTP POST method. Let's move on to figuring out why that's not working.
We're using the Imgur image upload API endpoint. This has one required parameter (image), and if we only want anonymous uploads all we need is a registered app. The upload method lets us send a simple URL to an image for upload, so let's try making an AJAX request to Imgur:
$.ajax
success: (data) -> console.log data
type: "POST"
data:
image: "http://placehold.it/300x500"
url: "https://api.imgur.com/3/upload"
headers:
Authorization: "Client-ID *************" # Don't forget to put your actual Client-ID here!
The next step is to try using the Filereader API to read the file from the form, and send that. Here's a CoffeeScript submit handler for that:
$('#file-form').submit (ev) ->
ev.preventDefault()
file = $('#file-form input[name=file]').get(0).files[0]
$.ajax
success: (data) -> console.log data
type: "POST"
data:
image: file
url: "https://api.imgur.com/3/upload"
headers:
Authorization: "Client-ID *************"
Finally, we can try using Dropzone to achieve the same thing:
$("div.dropzone").dropzone
success: (file, response) ->
console.log file
console.log response
paramName: "image"
method: "post"
maxFilesize: 2
url: "https://api.imgur.com/3/upload"
headers:
"Authorization": "Client-ID *************"
The Dropzone success callback gets two arguments: the file that was uploaded, and the response from the server. You'll probably be most interested in the latter; Imgur sends back an id and a link parameter on success that you can use to show the user their newly-uploaded image.
There's an example project for using the Imgur API from JavaScript available on Github here.