Skip to content

Windows authentication for internal applications on IIS

For internal applications, which means client and server are the on the same domain:

  1. Add the application on IIS.
  2. Disable Anonymous Authentication and enable Windows Authentication for this application on IIS.

When Anonymous Authentication is enabled and there is no other authentication mechanism implemented:

Request

GET http://<hostname>/<app>/api/<endpoint> HTTP/1.1
Host: <hostname>
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

Response

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Mon, 03 Apr 2017 15:48:07 GMT
Content-Length: 11658
<content>

After Anonymous Authentication is disabled and Windows Authentication is enabled:

Request

GET http://<hostname>/<app>/api/<endpoint> HTTP/1.1
Host: <hostname>
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

Response

HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Mon, 03 Apr 2017 15:46:53 GMT
Content-Length: 1293
<Not authorized content>

The server sends a 401 response with a WWW-Authenticate: Negotiate header. The client browser responds to “the challenge” by adding a Authorization: Negotiate <value> header to the same request and gets a successful response.

Request

GET http://<hostname>/<app>/api/<endpoint> HTTP/1.1
Host: <hostname>
Connection: keep-alive
Cache-Control: max-age=0
Authorization: Negotiate <3048 characters>
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

Response

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: false
X-Powered-By: ASP.NET
WWW-Authenticate: Negotiate <248 characters>
Date: Mon, 03 Apr 2017 15:46:53 GMT
Content-Length: 29
<content>

A AUTH_USER server variable is set with the logged in username as the value.

[Route("api/user")]
[HttpGet]
public string GetUser()
{
string username = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
username = username + ";" + HttpContext.Current.User.Identity.Name.ToString();
// username = Request.ServerVariables.Get("AUTH_USER");
username = username + ";" + ((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.ServerVariables.Get("AUTH_USER");
}