CORS development in localhost

Visual studio IDE comes up with built-in web server - IIS express(Casini), that allows to run the web application run with no special configurations on localhost (127.0.0.1). This speeds up the web application development and also removes the burden of configuring each developer's machine.

But still for certain application development scenarios like CORS headers, it would require manual addition of headers to the IIS Express configuration file.

Whenever an application is launched in IISExpress, it creates .vs folder in the same level usually project root folder where .sln file exists. Browsing the /.vs folder will contain the configuration files created by Visual Studio to help launching the web server. For modifying the IIS Express configuration, navigate inside /config folder and open applicationhost.config in any text editor (notepad or notepad++). You can add your CORS headers as part of the customHeaders within httpProtocol.

For an application that should access the images, scripts and make HTTP GET, POST, PUT, DELETE etc., without need for authentication. Then you can simply add * to the CORS header Access-Control-Allow-Origin. This will allow any domain to access other domain's resource. e.g., http://localhost:8081 can access the APIs on http://localhost:8082.

<httpProtocol>
   <customHeaders>
     <clear />
     <add name="X-Powered-By" value="ASP.NET" />
     <add name="Access-Control-Allow-Origin" value="*" />
     <add name="Access-Control-Allow-Headers" value="Content-Type" />
   </customHeaders>
</httpProtocol>

Sharing credentials between subdomains (or localhost with different port numbers):

In case your application, needs to share the cookies/credentials between sub-domains i.e., a.domain.com and b.domain.com OR in localhost environment between http://localhost:8081 and http://localhost:8082.

For example, The authentication endpoint exists on :8081, and application on :8082 raises a cross origin request for authentication to 8081. After successful authentication, the cookies (domain name specified as 'localhost') that are set by the authentication endpoint on 8081, will not be accessible to the application on 8082 which also exists on localhost

i.e., As a result, when subsequent XMLHttpRequest (AJAX)  made by 8082 will fail with HTTP status 403 (Forbidden). The browser will not attach the cookie even-though the domain name are same - localhost. This is due to the difference in the port number that set the cookie. Browser agents are so strict that they won't attach the cookies when the origin differs.

So for this situation, we need to set an additional CORS header Access-Control-Allow-Credentials with value true, and  also amend out Access-Control-Allow-Origin header with the exact domain name, protocol and port number as follows

<httpProtocol>
   <customHeaders>
     <clear />
     <add name="X-Powered-By" value="ASP.NET" />
	<remove name="Access-Control-Allow-Origin" />
	<!-- <add name="Access-Control-Allow-Origin" value="*" /> -->
	<add name="Access-Control-Allow-Origin" value="http://localhost:8082" />
	<add name="Access-Control-Allow-Headers" value="Content-Type" />
	<add name="Access-Control-Allow-Credentials" value="true" />
   </customHeaders>
</httpProtocol>

This will allow us to do the development, when the services/api with authentication and the client application existing on 2 different domains.

Firing of duplicate API / AJAX requests:

Whenever CORS is enabled, the browser will first send a preflight OPTIONS request to the cross-domain. As a result, you will notice that the actions or your endpoints are getting triggered twice.

In order to prevent duplicated action execution. You need to check if the HTTP request type = OPTIONS and for that specific request, just set the required CORS headers and send a blank response without executing the controller actions. This will allow the browsers to continue with the actual Cross-Origin request much faster and make effective use of server resource.

Further you can specify the number of seconds, the CORS response can be cached using Access-Control-Max-Age header, so that preflight will not be attempted by the user-agent(browsers) within that duration.

Related Posts