I have an Azure Storage Account (classic) and I enabled CORS through the portal in this way:
Now I have a Flutter Web App (PWA) that needs to get some images from this storage, but it gets CORS errors.
I also tried with a test web page with a simple jquery ajax call and I gets the same errors.
This is the jquery code:
$.ajax({
url: 'https://xxxx.blob.core.windows.net/test.jpg',
type: 'get',
success: function(data, status) {
console.log("Status: "+status+"\nData: "+data);
},
error: function (result) {
console.log(result);
}
});
The error message is:
Access to XMLHttpRequest at 'https://xxxx.blob.core.windows.net/test.jpg' from origin 'https://zzz.azurewebsites.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
How can I add the Response Header: access-control-allow-origin: *
Thanks.
As discussed in the chat, your CORS configuration is perfectly fine. The issue you are running into is because the browser had cached the CORS settings. Two things we discovered:
CORS settings max age was set at a very high value (86400 seconds) that would have made the browser cache the CORS settings for a longer duration. Deleting the CORS settings and recreating it with lower max age value along with deleting browser cache will fix that.
It is always helpful to try the AJAX request in a 2nd browser just in case the 1st browser has cached the CORS settings.
Related
I am looking for Integration of DocuSignApi with Angular. I am following these steps.
Angular Application
Backend Server using .net core Web API to handle and DocuSign api using nuget.
Can I achieve this?
Option 1 - Angular application - will hit - login method of middleware api application - middleware will communicate - docusign - after successful it will share details of logged in users.
Option 2 - Angular application - directly hit to docusign methods for this When I am doing like this
var url = "https://account-d.docusign.com/oauth/auth?response_type=token&scope=signature&client_id=XXXXXXXXXXXXXXX-01caXXXXXXXX&state=a39fh23hnf23&redirect_uri=http://localhost:81/";
return this._dataService.getThirdParty1(url, header)
.pipe(map((response: Response) => {
return response;
}));
- public getThirdParty(url) {
return this._httpClient.get( url).pipe().pipe(map(this.handleResponse)).pipe(catchError(this.handleError.bind(this)));
}
I am getting error
Access to XMLHttpRequest at 'https://account-d.docusign.com/oauth/auth?response_type=token&scope=signature&client_id=XXXXXXXXXXXXXXX-01ca8f1b220&state=a39fh23hnf23&redirect_uri=http://localhost:81/' from origin 'http://localhost:81' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
account-d.docusign.com/oauth/auth?response_type=token&scope=signature&client_id=XXXXXXXXXX-411a-9bb9-01ca8f1b220&state=a39fh23hnf23&redirect_uri=http://localhost:81/:1 Failed to load resource: net::ERR_FAILED
Please provide a way to check these options.
First, your issue is that you are making client-side calls to DocuSign from a different domain which validated CORS policy which is a security concern.
(Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading of resources. CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.)
Larry wrote extensively on this topic and here are some of the resources that can help.
Here is a three part series on the topic - https://www.docusign.com/blog/dsdev-building-single-page-applications-with-docusign-and-cors-part-1
Here is his code in GitHub showing you how to create a CORS gateway - https://github.com/docusign/blog-create-a-CORS-gateway
One other useful resource - https://www.cdata.com/kb/tech/docusign-odata-angularjs.rst
I have a Google Cloud Function. I created credentials for my project and authorized http://localhost & http://localhost:3000 as origins. I also have a Google user account that I gave the cloudfunctions.functions.invoke role to. I confirm this by going to the cloud function in the console and expand the "Cloud Functions Invoker" item and see my account listed there.
I can successfully access the function with curl.
curl https://[google-cloud-server]/test5 -H "Authorization: bearer my-identity-token"
However, if I try to invoke the function from my React app (I tried both axios and fetch), I get the following error....
Access to XMLHttpRequest at 'https://[google-cloud-server]/test5?a=b' from origin 'http://localhost:3000' 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.
A couple things to note...
There are no CORS problems if I make the function accessible to allUsers
Through logging, I have confirmed that, when secured, the request never makes it to the function where I have my CORS code for checking pre-flight OPTIONS. This makes sense as it is supposed to be secured by Google. But all documentation I find on Google Cloud functions talking about handling CORS-related stuff from within the function. Something is responding to my React app's request before it reaches my function. I have no idea what/where.
I added so many tags to this post because I really don't know which layer is causing the problem. I'm probably doing something really obvious/stupid, but I'm out of ideas!
Cloud function....
exports.test5 = (req, res) => {
console.log('function invoked');
// Set CORS headers for preflight requests
// Allows GETs from any origin with the Content-Type header
// and caches preflight response for 3600s
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
console.log('Determined it is OPTIONS request');
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Authorization');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
} else {
console.log('Main function body');
res.send('Hello World!');
}
};
Call from React client...
const config =
{
params: payload,
headers:
{
Authorization: `bearer ${window.IDENTITY_TOKEN}`
}
};
axios.get(url, config)
.then((res) => {
...
})
.catch((err) => {
handleError(err);
});
Any ideas?
Thanks
CORS preflight OPTION request does not have an Authorization header and Cloud functions IAM prevalidates the Authorization header and will not call the function if it is missing.Therefore in order to serve the CORS preflight response you have to allow allUsers access to your cloud function.
Edit
They updated the documentation
If you want to build a web app that is secured with Google Sign-in and
Cloud Functions IAM, you'll likely have to deal with Cross-Origin
Resource Sharing (CORS). CORS preflight requests are sent without an
Authorization header, so they will be rejected on all non-public HTTP
Functions. Because the preflight requests fail, the main request will
also fail.
To work around this, you can host your web app and function(s) on the
same domain to avoid CORS preflight requests. Otherwise, you should
make your functions public and handle CORS and authentication in the
function code.
Alternatively, you can deploy a Cloud Endpoints proxy and enable CORS.
If you want authentication capabilities, you can also enable Google ID
token validation, which will validate these same authentication
tokens.
I am trying to customize the UI page on Azure B2C using an Azure storage blob using this article. It needs to be CORS enabled. I have tested it using test-cors.org and I know it is not but I do not know how to set it
Ther article uses https://wingtiptoysb2c.blob.core.windows.net/b2c/wingtip/selfasserted.html which I test and returns a 200 but mine does not
https://bookssorted.blob.core.windows.net/b2c/selfasserted.html
This article talks about using this PUT https://myaccount.blob.core.windows.net/?restype=service&comp=properties HTTP/1.1 but how do I run this?
EDIT: I am using Azure Storage Explorer and I have these rules set on the blob but it is still not returning a http 200 from test-cors.org
EDIT2: this is the url that makes the request to the authentication policy which loads the page that makes the request to load the blob
https://login.microsoftonline.com/bookssorted.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_bookssortedAuthenticationPolicy&client_Id=35f308cd-8914-4035-9f62-cec7600c1727&nonce=defaultNonce&redirect_uri=https%3A%2F%2Flocalhost%2Fbookssorted%2Fsecure%2Fsuccess&scope=openid&response_type=id_token&prompt=login
EDIT3: headers as requested
In order for a cross-origin request to succeed, the request must match the CORS configuration. This includes the request origin, request headers & exposed (response) headers. Any mismatch there would result in request to fail.
If the origin is known, then that URL must be specified (including protocol & port number if applicable) in the CORS rule. If the origin is not known and you can specify * as the origin and all URLs will be able to make such requests.
Same thing goes for request headers and exposed headers. Since different requests to Azure Storage make use of different request headers and return different response headers, it is advisable to set the value for these as * in the CORS rule. This will ensure that all request/response headers are accepted.
I have a React app using axios library for handling request. So following the next post:
How to login with username/password using OAuth2 and microsoft login and HTTP request
I could perform the action on Postman.
Then I set up the axios library to perform the POST
const dataForBody = `${'grant_type=password&' +
'username='}${encodeURI(userName)}&` +
`password=${encodeURI(userPassword)}&` +
`client_id=${encodeURI(clientID)}&` +
`resource=${encodeURI('https://graph.microsoft.com')}&` +
`client_secret=${encodeURI(clientSecret)}`;
const messageHeaders = {
'Content-Type': 'application/x-www-form-urlencoded'
};
axios({
method: 'post',
url: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
headers: messageHeaders,
data: dataForBody,
})
.then((response) => {
});
but I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at
https://login.microsoftonline.com/{tenant}/oauth2/token.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I tried adding:
'Access-Control-Allow-Origin': 'https://login.microsoftonline.com',
to the headers, but it did not work.
So adding Allow-Control-Allow-Origin: * chrome extension fixed my problem.
The thing is, my app is to be published on azure, so I tested the request on other web browsers and it did not work. So I don't want my users to install the extension.
Is there something wrong with my request? Why postman can do it without setting up headers?
Is there any other approach to achieve it?
PS: I read about using adal.js but I dont want to use the login screen from microsoft, because I know user and pass for the app, and I want to avoid manual login.
The problem you face is due to you trying to call the token endpoint via AJAX, which it won't accept due to the CORS header missing. You can't add it, it's missing from the response from Azure AD.
What you need to do is instead of getting the access token from the token endpoint, you must use the OAuth Implicit Grant Flow. This flow allows you to get the tokens directly in the authorization stage, and is especially designed for JavaScript-based apps. More info here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-dev-understanding-oauth2-implicit-grant.
What this means is that you can't use the Password Grant Flow as you are doing now, unless you make the calls from your backend instead of the frontend.
When enabling CORS on Azure blob storage, almost everything can be set but the "...Allow-Credentials" header, which is always true.
So when using a wildcard for the origin-header, the pre-flight request works fine and converts the wildcard into the actual origin.
But the subsequent GET request does not convert the wildcard and returns the following combination:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
which is illegal in Chrome (and probably other browsers, too). The error is
XMLHttpRequest cannot load ...
A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true.
Origin 'http://localhost' is therefore not allowed access.
In the new WebAPI v2 CORS package wildcards are replaced with the actual origin.
Also, why would I need credentials such as cookies in a request to the blob storage? Better turn it off.
How could I fix that when I want to use the origin wildcard?
UPDATE
Here's the initialize code I run on App_Start
public static void Initialize()
{
// Azure blob storage settings
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AzureStorage"].ConnectionString);
var client = storageAccount.CreateCloudBlobClient();
var serviceProperties = client.GetServiceProperties();
serviceProperties.Cors = new CorsProperties();
serviceProperties.Cors.CorsRules.Add(new CorsRule()
{
AllowedHeaders = new List<string>() { "*" },
AllowedOrigins = new List<string>() { "*" },
AllowedMethods = CorsHttpMethods.Get,
ExposedHeaders = new List<string>() { "*" },
MaxAgeInSeconds = 3600
});
client.SetServiceProperties(serviceProperties);
}
The error that you encountered is due to setting withCredentials property on the xmlhttpreqeust to true ,in that case the browser will reject wildcard Access-Control-Allow-Origin.
In the new WebAPI v2 CORS package wildcards are replaced with the
actual origin.
Returning wildcard is the right thing to enable caching, take a look at the following scenario:
User A sends GET request to a public blob on MAS (Microsoft Azure Storage).
If you are using a CDN/Proxy to cache public resources which is a best practice then the CDN will cache the blob with Access-Control-Allow-Origin set to '*'.
Now User B sends the same request to MAS and gets the response from the cache instead, in that case since the cached blob has wildcard Access-Control-Allow-Origin the browser will allow that request and you don't need to hit MAS servers.
Now in the other case that you always return the actual origin, you can't cache that resources for multiple clients since the browser will fail the CORS request if the Access-Control-Allow-Origin has an actual origin that differs from request origin header.
Also, why would I need credentials such as cookies in a
request to the blob storage? Better turn it off.
You would need the credentials since one way to send authenticated requests is using the Authorization header, if the preflight request doesn't allow that then the browser should fail actual requests with Authorization header.
It actually does work when
withCredentials == false
on the XmlHttpRequest object. In my case this setting got messed up in the js framework I'm using.