How can I retrieve Basic Authentication credentials from the header?
I am trying to write some simple tests User Authentication mechanism which uses Basic Authentication. How can I retrieve the credentials from the header?
string authorizationHeader = this.HttpContext.Request.Headers["Authorization"];
Where do I go from here? There are several tutorials but I new to .NET and authentication, could you explain in your answer exactly step-by-step the what and why you are doing.
From my blog:
This will explain in detail how this all works:
Step 1 - Understanding Basic Authentication
Whenever you use Basic Authentication a header is added to HTTP Request and it will look similar to this:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Source: http://en.wikipedia.org/wiki/Basic_access_authentication
"QWxhZGRpbjpvcGVuIHNlc2FtZQ==" is just "username:password" encoded in Base64(http://en.wikipedia.org/wiki/Base64). In order to access headers and other HTTP properties in .NET (C#) you need to have access to the current Http Context:
HttpContext httpContext = HttpContext.Current;
This you can find in System.Web namespace.
Step 2 - Getting the Header
Authorization header isn't the only only one in the HttpContext. In order to access the header, we need to get it from the request.
string authHeader = this.httpContext.Request.Headers["Authorization"];
(Alternatively you may use AuthenticationHeaderValue.TryParse as suggested in pasx’s answer below)
If you debug your code you will see that the content of that header looks similar to this:
Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Step 3 - Checking the header
You've already extracted the header now there are several things you need to do:
- Check that the header isn't null
- Check that the Authorization/Authentication mechanism is indeed "Basic"
Like so:
if (authHeader != null && authHeader.StartsWith("Basic")) {
//Extract credentials
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}
Now you have check that you are have something to extract data from.
Step 4 - Extracting credentials
Removing "Basic " Substring
You can now attempt to get the values for username and password. Firstly you need to get rid of the "Basic " substring. You can do it like so:
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
See the following links for further details:
- http://msdn.microsoft.com/en-us/library/system.string.substring(v=vs.110).aspx
- http://msdn.microsoft.com/en-us/library/t97s7bs3(v=vs.110).aspx
Decoding Base64
Now we need to decode back from Base64 to string:
//the coding should be iso or you could use ASCII and UTF-8 decoder
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
Now username and password will be in this format:
username:password
Splitting Username:Password
In order to get username and password we can simply get the index of the ":"
int seperatorIndex = usernamePassword.IndexOf(':');
username = usernamePassword.Substring(0, seperatorIndex);
password = usernamePassword.Substring(seperatorIndex + 1);
Now you can use these data for testing. Good luck!
The Final Code
The final code may look like this:
HttpContext httpContext = HttpContext.Current;
string authHeader = this.httpContext.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic")) {
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
int seperatorIndex = usernamePassword.IndexOf(':');
var username = usernamePassword.Substring(0, seperatorIndex);
var password = usernamePassword.Substring(seperatorIndex + 1);
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}
Just adding to the main answer, the best way to get rid of the "Basic" substring is to use AuthenticationHeaderValue Class:
var header = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentials = header.Parameter;
It will throw a FormatException if the content of the header is not valid, e.g.: the "Basic" part is not present.
Alternatively if you do not want to have exception, use AuthenticationHeaderValue.TryParse