azure-functions-host: Cross origin http request CORS fails with response header missing 'Access-Control-Allow-Credentials: true'
Cross origin http request (CORS) to Azure function does not return ‘Access-Control-Allow-Credentials:true’. Is there a way to add custom headers?
Details
- It is a nodeJS function
- Only one CORS entry: ‘http://localhost’
- Tried with both AJAX and Javascript API
- Authentication with google OAUTH
Error: Response to preflight request doesn’t pass access control check: Credentials flag is ‘true’, but the ‘Access-Control-Allow-Credentials’ header is ‘’. It must be ‘true’ to allow credentials. Origin ‘http://localhost’ is therefore not allowed access.
Mostly followed as per the following post except mine is CORS: https://shellmonger.com/2016/02/12/using-azure-app-service-authentication-with-a-web-application/
Code
let options = {
mode :'cors', //tried both with and without
method: 'GET',
credentials: 'include',
cache: 'no-cache'
};
fetch('https://<function-name>.azurewebsites.net/.auth/me.', options).then((response) => {
this.logger.debug('[checkauth-callback-1]: Response = ', response);
if (!response.ok && response.status !== 401)
throw new Error('Invalid Response from Config Endpoint', response);
if (response.status === 401)
return false;
return response.json();
})
**also tried:**
headers:new Headers({
'content-type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Credentials':true,
'Access-Control-Allow-Origin':true
'''
A similar issue raised on stackoverflow:
http://stackoverflow.com/questions/39215513/how-to-add-customer-http-header-in-response-from-azure-function
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 22
- Comments: 44 (13 by maintainers)
I have finally managed to get around the issue. The trick is to remove all the CORS entries from Azure Functions app and handle it directly in your code. Thanks to the tip shared in post regarding azure app service.
module.exports = function(context, req) { context.log('Node.js HTTP trigger function processed a request. RequestUri=%s', req.originalUrl); f (req.query.name || (req.body && req.body.name)) { context.res = { // status: 200, /* Defaults to 200 */ body: {name: (req.query.name || req.body.name) } }; } else { context.res = { status: 400, body: "Please pass a name on the query string or in the request body" }; } context.res.headers = { 'Access-Control-Allow-Credentials' : 'true', 'Access-Control-Allow-Origin' : 'http://localhost', 'Access-Control-Allow-Origins' : 'http://localhost', 'Content-Type': 'application/json' }; context.done(); };
And from client side javascript:
` var request = new Request(url, { method: ‘GET’, credentials: ‘include’, cache: ‘no-cache’, mode:‘cors’ });
fetch(request) .then(function(response) { console.log(response); response.json().then(function(data){ console.log(data); alert(data) }); }) .catch(function(err){ console.log(err); }) ;`
I close this issue for now, but it will be great if we can specify additional headers at the application level.
@ricklove Can you please clarify what you did?
This is my code:
When I clear all URLS from API -> CORS in the Azure Portal the “Access-Control-Allow-Credentials” header works properly and is set to true, but “Access-Control-Allow-Origin” is not passed through and therefore is not set.
When I set API -> CORS in the Azure Portal to my domain name, that header is set properly, but Access-Control-Allow-Credentials is not set.
Yes, sorry for the delay! We recently added support for Access-Control-Allow-Credentials. See our announcement here: https://azure.microsoft.com/en-us/blog/simplifying-security-for-serverless-and-web-apps-with-azure-functions-and-app-service/.
Here is the note from the documentation:
A heads up:
The workaround to remove all CORS in the portal no longer appeared to work.
I discovered that this was because I had enabled the new Azure Functions Proxies (preview).
Upon disabling proxies, it worked again.
So, if you are having trouble getting manual CORS to work:
@pauldalyii would you mind opening a separate issue for your request? That will allow us to better track it.
@TechInceptions this is the name of an ARM (Azure Resource Manager) property. See this tutorial for how to configure CORS in Azure App Service (works exactly the same for Functions): https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-rest-api#enable-cors
Example CLI command:
This can also be done via the Azure Resource Explorer web interface.
Done on my end. @cgillum - please leave comments in the UserVoice item about approach and any timing we can share, when that becomes available.
I feel like the request has been misunderstood and needs to be reconsidered. This workaround isn’t a solution, we need either a way to disable Azure’s CORS responses and remove the warning regarding functions.azure.com, or the Azure CORS support needs to be extended to support the -Credentials header. Citing an article by a Microsoft developer for a workaround isn’t a closing statement for declining. If anything it highlights that the issue is known and needs to be fixed.
I understand that this is a Web App issue and not a Functions issue, however, I hope the developers for Azure Functions can help us get this resolved.
Kind regards, Josh.
@safihamid Wow that was fast.
Tell the team thanks for your work!
@safihamid Yes, of course, I was using proxies so it was unfortunate that I had to disable them because I could find no workaround for the CORS problem.
Setup
Remove all entries from the portal CORS panel. (Including the * wildcard entry.) This is required in order to bypass the CORS logic as mentioned above.
Code
In a Node.JS http function:
Repro Problem
You will need to call this function with an ajax cross origin call (from a different domain) in order to trigger the CORS browser behavior.
I just wanted to talk a little bit about the “security implications” of cookies vs. tokens. There seems to be this impression that tokens are somehow more secure than cookies. I disagree with this. Both have their advantages and disadvantages and I think cookies, when handled properly, come out slightly ahead. I want the “Access-Control-Allow-Credentials” header because we use cookies, and we are a security consulting company. This doesn’t mean we’re right, but I’ve thought a decent bit about this.
From a security stand-point, utilizing tokens completely prevents Cross-Site Request Forgery (CSRF) attacks. This is the main, and only real security advantage I can see that tokens have over cookies. They work to prevent CSRF attacks because a CSRF vulnerability is reliant on the web-browser automatically adding the session token when a request is sent for a given domain, even from an untrusted domain. Since tokens have to be added by JavaScript code running in the context of the domain, CSRF is stopped by default.
However, being immune to this problem comes at a cost. Since JavaScript has to be able to access and send the session token, this means that Cross-Site Scripting (XSS) (Should the vulnerability exist) will ALWAYS be able to access the session token. While XSS’s possibilities of actually being able to execute are reduced with a JSON application that properly sets the Content-Type to application/json; XSS is still one of the most common vulnerabilities in web applications. With tokens you are guaranteed that the worst possible exploit of XSS is available, the stealing of the session token. This is a huge negative, that I believe completely counters the positive of stopping CSRF. There is no way to use a token, and avoid this exploit scenario IF XSS is found in the application.
Cookies on the other hand are vulnerable by default to CSRF since any web-browser will automatically add the cookie to a request destined for a given domain. You can prevent this behavior, however, by sending CSRF tokens from the framework itself to the server. This will mean you are sending both a session cookie and a CSRF token; but when you do you have completely blocked CSRF.
In addition, with cookies you have the option of setting the “httpOnly” flag on cookie creation. This flag makes it impossible for JavaScript to read the cookie value, even though that value is still sent to the server for authentication. This means that even if a XSS vulnerability is discovered, it will NOT be possible to take advantage of the worst exploit for that vulnerability; stealing the session token. The attacker still will be able to utilize the XSS to grab the CSRF token, and send a fraudulent request to the server on behalf of the user; but this would also be possible with token auth.
As a result if you use cookies, there are settings and ways to mitigate the additional risks posed with using that choice. If you use tokens, you do not have that option. That’s just my 2 cents on this topic 😃.
If there are security advantages of tokens I’m missing; please let me know. I’m definitely open to learning something new.
In any case, thank-you for re-opening the new feature request to get this into the product! It is very much appreciated!
@burma-shave Thanks for that info, a quick search confirms: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
We’ll look into adding support for this. Thanks for your patience on this issue. @odvoskin can we update the feedback response? I think the case has been made that this feature is needed.
Good catch @ahmelsayed. I’m still not sure about the original issue, there was a lot of back-and-forth. Can the original posters please comment?
@ricklove thanks for the repro, we have a fix for Proxy for this and will release it in the next few days. I will notify this thread when the fix is live.
@ricklove Thank-you. Implementing your code helped me isolate the issue.
Apparently because I cleared out the “deployments” directory of logs, it actually caused my future deployments to say they were working, but actually fail to put my code into wwwroot. (I’m continuously deploying based on a git repository). As a result when I thought I was putting other code out to add new headers… I actually wasn’t.
Once I changed out my code to mimic your code it became absolutely clear that my changes weren’t doing anything, and I explored further to find the real issue. I’m still trying to get the code deployed correctly, but I’m pretty sure that was the real reason why I had the results.
@satjinder Thanks for the tip that removing all CORS entries allows for the headers to be set manually in the response in code.
That solved my problem, and I can have my own custom logic for checking valid domains now.
Note: Now I get a warning that CORS is not configured for the functions domain:
Is there any problem with ignoring this?
Have you tried enabling CORS via the Function App Settings?