CORS with Basic or Windows Authentication
Update
Along with one of our customers I rethought the approach below to integrate everything into the module, see the sample for more details.
Intro
In the ServiceAPI help there is a sample on how to use the CORS feature. There are some limitations in this feature that make it unlikely to work for most ServiceAPI users.
Preflight
When using a browser, maybe via jQuery, the odds are that a preflight request will be sent. This is an HTTP OPTIONS request to confirm that the correct CORS headers are returned. This request is sent without any authentication. The problem when using IIS basic or integrated authentication is that this request will be rejected.
The solution
The solution is not to use the CORS feature at all but to fall back on traditional ASP.Net techniques, as detailed in this very helpful post .
Module
Firstly write a, ASP.Net Module to allow us to get into the pipeline before IIS rejects our request, compile this in Visual Studio and place the DLL in the ServiceAPI bin folder. All OPTIONS requests will now be returned with the status 200.
public class CORSModule : IHttpModule { public void Dispose() { } public void Init(HttpApplication context) { context.PreSendRequestHeaders += delegate { if (context.Request.HttpMethod == "OPTIONS") { var response = context.Response; response.StatusCode = (int)HttpStatusCode.OK; } }; } }
Configure module
Now we wire the module into our service in the system.webServer\modules element...
<modules runAllManagedModulesForAllRequests="true"> <add name="CORSModule" type="CORSModule" /> </modules>
Set CORS headers
Lastly we add the CORS headers to system.webServer\httpProtocol
<customHeaders> <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" /> <add name="Access-Control-Allow-Origin" value="http://localhost" /> <add name="Access-Control-Allow-Headers" value="Content-Type,Authorization" /> <add name="Access-Control-Allow-Credentials" value="true"/> </customHeaders>
Test it out
Once you have implemented the above the jQuery code like this should be successful in accessing a ServiceAPI instance using basic authentication.
$.ajax({ beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", "Basic " + btoa("USERNAME" + ":" + "PASSWORD")); }, url: "http://davidc2012r2/ServiceAPI82/Record/1?&properties=RecordTitle", type: 'GET', dataType: 'json', }) .done(function (response, statusText) { if (statusText === "success") { alert("Record named: " + response.Results[0].RecordTitle.Value + " was found."); } }) .fail(function (xhr) { var err = eval("(" + xhr.responseText + ")"); alert(err.ResponseStatus.Message); });