HttpWebRequest and PreAuthentication

The topic of this post is PreAuthentication.

HTTP Webservers support multiple authentication options. On Windows, IIS supports Basic, NTLM, Digest, Negotiate (a.k.a Integrated Windows Authentication). Of these, Basic & Kerberos support PreAuthentication.

"PreAuthentication" is sometimes misunderstood to mean "Send credentials on the very first request". That is not the way it works. For Preauthenticate to work, the following things have to happen:

1) You make a webrequest to a server. You might (or might not) have specified credentials on the first request.

2) The server want to authenticate the request you are making. So it replies with a 401.

3) The client does the authentication handshake with the server, and sends your credential.

4) If "Basic" was chosen as the authentication scheme by the client, then Pre-Authentication is enabled for this request. So, every subsequent request from now on to the same Uri-Prefix will result in the credentials being sent preemptively.

The main thing to note here is: It requires atleast one request before the client can do pre-authentication. Credentials are not automatically sent on the first request if PreAuthenticate is true.

If you want to force credentials to be sent on the first request (and thus avoid the first auth handshake), you can set credentials manually on the request:

WebRequest req = WebRequest.Create("http://....");

string cre = String.Format("{0}:{1}", username, password);

byte [] bytes = Encoding.ASCII.GetBytes(cre);

string base64 = Convert.ToBase64String(bytes);

req.Headers.Add("Authorization", "basic " + base64);

WebResponse resp = req.GetResponse();

This will set the authorization header on the request, and send it on the first request itself. If the credentials are correct, the first handshake will not happen.

However, remember that you have to use this code to set the authorization header on every request. This is because we bypassed the authentication handshake, and HttpWebRequest has no knowledge that the server requires authentication. So it wont do pre-authentication by itself anymore.

The recommended way to get preauthentication is to set the credentials on the request, set PreAuthenticate=true, and send the request. Once the first authentication handshake happens, and credentials are accepted by the server, preauthentication will happen behind the scenes for every request to the same Uri-Prefix.