12/27/15

API OAuth Token Access-Control-Allow-Credentials header is empty

When implementing an Azure API App using MVC Web API with OAuth Bearer Token Authorization, we came across this 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://domain.com' is therefore not allowed access.


This error is a result of an AJAX request to an Azure API App with Cross-origin resource sharing (CORS) support. We looked at the response headers and noticed that the 'Access-Control-Allow-Credentials header was actually blank which does not allow the browser to continue since it is a security policy. The code that makes the request is shown next:


$.ajax({
                type: 'POST',  async:true,
                url: 'https://someapp.azurewebsites.net/token',
                dataType: "json",
                contentType: 'application/x-www-form-urlencoded; charset=utf-8',
                xhrFields: {
                    withCredentials: true
                },
                headers: {
                    'Authorization': 'Basic ' + appInfo                   
                },             
                success: function (result) {
                    var token = result.access_token;
                    //…                  
                },
                error: function (req, status, error) {
                    if (typeof(req) != 'undefined') {
                        var msg = status || req.responseJSON.error;
                        //…
                    }                  
                }
        });


The same code works OK when testing on the test environment (NO Azure). We can see how the headers for cross domain and credentials are included in the response headers. This confirms that outside of Azure, the CORS configuration in the application is correct.


Response Headers

Access-Control-Allow-Headers
Access-Control-Allow-Origin
Access-Control-Allow-Credentials


In Azure, we need to configure the CORS settings on the Azure Management UI which overrides any application CORS settings. This configuration outside of our web API application causes this problem with the header.

Since we are using OAuth bearer token security, we pass the client information as a header, and we do not use any type of cookies for security. This means that we do not need to use the withCredentials AJAX parameter.


withCredentials

Standard CORS requests do not send or set any cookies by default. In order to include cookies as part of the request, you need to set the XMLHttpRequest’s .withCredentials property to true. The server must also enable credentials by setting the Access-Control-Allow-Credentials response header to "true"


Once the withCredentials parameter is removed from the AJAX request, the Azure API App started to work properly. This is how the code looks now:


$.ajax({
                type: 'POST',  async:true,
                url: 'https://someapp.azurewebsites.net/token',                
                dataType: "json",
                contentType: 'application/x-www-form-urlencoded; charset=utf-8',
                //xhrFields: {
                //    withCredentials: true
                //},
                headers: {
                    'Authorization': 'Basic ' + appInfo                   
                },             
                success: function (result) {
                    var token = result.access_token;
                    //…                  
                },
                error: function (req, status, error) {
                    if (typeof(req) != 'undefined') {
                        var msg = status || req.responseJSON.error;
                        //…
                    }                   
                }
            });



The resolution is to configure the request in a way that matches the expected response header from the server. In this case, there was no need to exchange security over cookies since this is done using a token. This is the solution for this particular case, but there could be other root cause that manifest in a similar problem.  

12/13/15

404 Error axd HTTP Handler

This error is common when a previously working web app has been migrated to another server or a cloud hosted environment, and it is now showing the HTTP 404 (Not Found) error.  To figure out the root cause and solution, let’s take a look at how the web app was configured initially. We will then take a look at the solution.

HTTP Handlers Configuration

When we look at the web.config settings we can find this entry:


<system.web>
            
    <httpHandlers>
<add verb="*" path="myhandler.axd"   type="MyHandler"/>
    </httpHandlers>
</system.web>



This setting indicates that there is an HTTP handler defined by the type MyHandler. It also tells IIS to allow all requests (verbs = GET, POST etc.) with the route myhandler.axd as this handler should manage the requests. This is important because this also works as a mime type setting, so there is no need to add a mime type for this file extension on IIS. It is important to notice that this setting only works for IIS 5, 6 and IIS7 Classic Mode.  

If we migrate the app to a hosting service that has IIS7 (*Note that you can even notice this problem running on IIS7 express if you upgrade Visual Studio), we can probably recreate the 404 error.

There are two solutions to this problem:
  1. Use IIS7 Classic Mode
  2. Update the Web.config for IIS7 Support

Use IIS7 Classic Mode

If access to IIS is available, we can just change application pool Managed Pipeline Mode property to Classic, and the handler should be invoked properly. This can also be done for IIS Express by looking at the project properties - Manage Pipeline Mode setting.

Updating Web.config for IIS7 Support

In the case of cloud hosting, we need to make the change in the web.config by adding a new configuration section for HTTP handlers (*Note: This is used for IIS7 and future version). Let’s take a look at how that should look:



<system.webServer>
       <handlers>                
      <add name="myhandler" verb="*" path="myhandler.axd" type="ozkary.MyHandler"   preCondition="integratedMode"/>  
    </handlers>
</system.webServer>



This setting indicates that we have a handler that should manage the requests in integrated mode. This is how HTTP handlers are configured when running on IIS7.  If we deploy again and load the site, we should no longer see the 404 error.

We should notice that these settings can co-exist in the web.config, but only one will be loaded which is dependent on your IIS environment.  This approach can let us develop on previous version of IIS and target more recent version on our deployments.

12/12/15

Publish MVC Web App on Azure Virtual Directory

Azure Web Apps are deployed as a new website on the Azure cloud. For those who have control of the server, this is similar to adding a new website on an IIS server. What if we need to deploy another web app on Azure, but we do not want to create a new web site?  Well the answer is to create a virtual directory and deploy the web app there. Let’s take a look at how we can do that using the Azure management website.  

We start by looking at a Web App that is already deployed on Azure. We need to look at the settings as shown below:

Azure Web App Settings
The image above shows the Virtual application and directories settings. This is the area where we can add a virtual directory that we can later target or use for another deployment. Let’s add a virtual directory named Admin. We will use this for the administration module of the web app. We need to enter the virtual directory name, physical path under wwwroot and check that we want this as an application which we need if we want to allocate the web app to an app pool. We can now save the changes, and the result should look as follows:

Admin Virtual Directory
We are now ready to show how to deploy this. Let's go over Visual Studio, open the solution and take a look at the publishing profile for the original app. Notice the Site Name and Destination URL settings.

Publish Profile Settings
Since we are now deploying to the same web app site and URL, we just need to append the virtual directory information (/Admin) as shown below:


Publish Profile - Virtual Directory

We can now just press the publish button, and we have one Azure web app instance hosting two web apps with one at the wwwroot and the other on the virtual directory off of wwwroot.

I hope this tip provides some insight for your web app deployment strategies on Azure.