Cook Computing

PreAuthenticate Property of WebRequest - Problem

January 29, 2009 Written by Charles Cook

There is a common misunderstanding about how the PreAuthenticate property of .NET's System.Net.WebRequest class works, for example when using Basic Authentication. In this post I'll explain how it actually works and in the next post I'll describe how to use WebRequest to get the behaviour that is often erroneously expected when PreAuthenticate is used. Say this code is used to retrieve two HTTP resources:


using System;
using System.IO;
using System.Net;

class Program
{
  static string Get(string uri)
  {
    WebRequest req = WebRequest.Create(uri);
    req.Credentials = new NetworkCredential("user", "password", 
        "cookcomputing.com");
    req.PreAuthenticate = false; // default for WebRequest
    Stream stm = req.GetResponse().GetResponseStream();
    string ret = new StreamReader(stm).ReadToEnd();
    return ret;
  }

  static void Main(string[] args)
  {
    Console.WriteLine(Get("http://localhost:81/foo/foo.html"));
    Console.WriteLine(Get("http://localhost:81/foo/bar.html"));
  }
}

There will be four round-trips between the client and server (for the time being assume the server does not have HTTP Keep-Alive enabled):

  • Client: GET /foo/foo.html HTTP/1.1
  • Server: HTTP/1.1 401 Access Denied
    WWW-Authenticate: Basic realm=" cookcomputing.com"
  • Client: GET /foo/foo.html HTTP/1.1
    Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh
  • Server: HTTP/1.1 200 OK
  • Client: GET /foo/bar.html HTTP/1.1
  • Server: HTTP/1.1 401 Access Denied
    WWW-Authenticate: Basic realm="cookcomputing.com"
  • Client: GET /foo/bar.html HTTP/1.1
    Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh
  • Server: HTTP/1.1 200 OK
The common mistake with PreAuthenticate is to assume that if we enable it there will only be one round-trip for each request.


    req.PreAuthenticate = true;

In fact this is what actually happens:

  • Client: GET /foo/foo.html HTTP/1.1
  • Server: HTTP/1.1 401 Access Denied
    WWW-Authenticate: Basic realm=" cookcomputing.com"
  • Client: GET /foo/foo.html HTTP/1.1
    Authorization: Basic c3RvY2tsZXkuYXZheWEuY29tXGNoY29vazpBcmVuaWcxNjAh
  • Server: HTTP/1.1 200 OK
  • Client: GET /foo/bar.html HTTP/1.1
  • Server: HTTP/1.1 200 OK
i.e. we still have two round-trips for the first request but only one round-trip for the second request. Therefore if you are making single requests to a server the use of PreAuthenticate does not make a difference. You will still get a 401 Access Denied response from the server which requires another HTTP request to the server containing the authorization header based on the realm specified by the server.

Note that if the server has enabled HTTP KeepAlive and the default value of true for HttpWebRequest.KeepAlive has not been changed, then assuming the connection remains open for the second request, the successful authorization for the first request will still apply and the use of PreAuthenticate is not required.