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)

Commits related to this issue

Most upvoted comments

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:

module.exports = function(context, req){
    var shared = require('../auth-shared-libraries');
    var cors_url = "https://mywebsite.azurewebsites.net"
    context.res =  {
        status: 200,
        headers: {
            "Access-Control-Allow-Credentials" : "true",
            "Access-Control-Allow-Origin" : cors_url,
            "Content-Type" : "application/json"
        },
        body : { "status" : "alive"}
    }
    context.done();
}

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:

If your app requires credentials such as cookies or authentication tokens to be sent, the browser may require the ACCESS-CONTROL-ALLOW-CREDENTIALS header on the response. To enable this in App Service, set properties.cors.supportCredentials to true in your CORS config. This cannot be enabled when allowedOrigins includes ‘*’.

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:

  • remove all CORS entries in the portal
  • make sure Proxies is disabled

@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:

az resource update \
    --name web \
    --resource-group myResourceGroup \
    --namespace Microsoft.Web \
    --resource-type config \
    --parent sites/<app_name> \
    --set properties.cors.allowedOrigins="['http://localhost:5000']" \
    --set properties.cors.supportCredentials=true

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:

    context.done(null, {
        status: 200,
        headers: {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin' : origin,
            'Access-Control-Allow-Credentials'], 'true'
        },
        body: {
            ok: true
        },
    });

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.

  • If proxies is disabled, the above function will respond with the correct Access-Control headers.
  • If proxies is enabled, the above function will respond with ‘Access-Control-Allow-Origin’ = ‘*’ (but wildcard origin is not allowed for ‘Access-Control-Allow-Credentials’ == ‘true’ , i.e. ajax - withCredentials).

There were some concerns about the security implications of supporting such a feature, and we’re discussing that internally now. One reason why we didn’t expect this to be a problem is that we expected most SPA apps to use authentication tokens instead of cookies

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

The Access-Control-Allow-Credentials response header indicates whether or not the response to the request can be exposed to the page. It can be exposed when the true value is returned.

Credentials are cookies, authorization headers or TLS client certificates.

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:

    ERROR: CORS is not configured for this function app. Please add https://functions.azure.com to your CORS list.

Is there any problem with ignoring this?

Have you tried enabling CORS via the Function App Settings?