How to Add Basic Authentication to an ASP.NET Core Application: OAuth Security - Part 1

15th December 2020

Adding Basic Authentication to an ASP.NET Core application is relatively straight forward to do.

Basic Authentication can be used as security when generating an OAuth bearer token.

In addition, it can be used to restrict access to staging websites. This is so search engines cannot accidently crawl a staging website.

We are going to have a look at how Basic Authentication works, and how we can go about setting it up in an ASP.NET Core application.

How does Basic Authentication Work?

Basic Authentication works by adding an Authorization header into a HTTP request.

The value of the Authorization header must be Basic, followed by a space, followed by the username and password separated by a colon. The username and password are encoded using Base64.

For example, if the username is roundthecode and the password is roundthecode, the username and password would be presented like this:

roundthecode:roundthecode

Using Base64 encoding, this would encode the value into the following:

cm91bmR0aGVjb2RlOnJvdW5kdGhlY29kZQ==

So, the full value of the HTTP request Authorization header would be as follows:

Basic cm91bmR0aGVjb2RlOnJvdW5kdGhlY29kZQ==

We can use the Base64 Encode and Decode website to test this out.

How to Setup Basic Authentication in a ASP.NET Core Application?

Now that we have an understanding of how Basic Authentication works, we are going to go ahead and set it up in an ASP.NET Core application.

BasicAuthorization Attribute

The first thing we need to do is to create a BasicAuthorization attribute.

This attribute will be designed to be used in an MVC controller. We can wrap it around a particular action, or wrap it around a whole controller.

The attribute will inherit the AuthorizeAttribute class. When we create an instance of this attribute, we need to be able to set up a policy name. This is something we will have a look at later on.

// BasicAuthorizationAttribute.cs
public class BasicAuthorizationAttribute : AuthorizeAttribute
{
	public BasicAuthorizationAttribute()
	{
		Policy = "BasicAuthentication";
	}
}

AuthenticatedUser Class

Next, we want to create an AuthenticatedUser class. This will allow us to determine the identity of the user that has been authenticated.

The AuthenticatedUser class needs to inherit the IIdentity interface. As a result, we need to include three properties in our AuthenticatedUser class.

We need to set the authentication type, whether the user has been authenticated and the user's name.

// AuthenticatedUser.cs
public class AuthenticatedUser : IIdentity
{
	public AuthenticatedUser(string authenticationType, bool isAuthenticated, string name)
	{
		AuthenticationType = authenticationType;
		IsAuthenticated = isAuthenticated;
		Name = name;
	}

	public string AuthenticationType { get; }

	public bool IsAuthenticated { get;}

	public string Name { get; }
}

BasicAuthenticationHandler Class

The final thing we need to build is the BasicAuthenticationHandler class.

This is where we need to build the functionality as to allow the user to be authenticated or not.

The first thing we need to do is to check if there is a Authorization header present in the request headers.

Assuming there is, we need to check if it's been formatted properly. As discussed earlier, the Authorization header value must start with the word "Basic" followed by a space. This is then followed by a Base 64 encoding of the username and password.

Once we have got through that step, we can go ahead and decode the Base 64 string. This will then give us our username and password seperated by a colon.

It's worth noting that the username cannot have a colon, but the password can. This is because our code only splits the first colon and ignores any subsequent colons.

Assuming we are happy with the username and password, we can go ahead and create our user. Afterwards, we add that user to our claims principal which we pass as part of our successful authentication result.

// BasicAuthenticationHandler.cs
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
	public BasicAuthenticationHandler(
		IOptionsMonitor<AuthenticationSchemeOptions> options,
		ILoggerFactory logger,
		UrlEncoder encoder,
		ISystemClock clock
		)
: base(options, logger, encoder, clock)
	{
	}

	protected override Task<AuthenticateResult> HandleAuthenticateAsync()
	{
		Response.Headers.Add("WWW-Authenticate", "Basic");

		if (!Request.Headers.ContainsKey("Authorization"))
		{
			return Task.FromResult(AuthenticateResult.Fail("Authorization header missing."));
		}

		// Get authorization key
		var authorizationHeader = Request.Headers["Authorization"].ToString();
		var authHeaderRegex = new Regex(@"Basic (.*)");

		if (!authHeaderRegex.IsMatch(authorizationHeader))
		{
			return Task.FromResult(AuthenticateResult.Fail("Authorization code not formatted properly."));
		}

		var authBase64 = Encoding.UTF8.GetString(Convert.FromBase64String(authHeaderRegex.Replace(authorizationHeader, "$1")));
		var authSplit = authBase64.Split(Convert.ToChar(":"), 2);
		var authUsername = authSplit[0];
		var authPassword = authSplit.Length > 1 ? authSplit[1] : throw new Exception("Unable to get password");

		if (authUsername != "roundthecode" || authPassword != "roundthecode")
		{
			return Task.FromResult(AuthenticateResult.Fail("The username or password is not correct."));
		}

		var authenticatedUser = new AuthenticatedUser("BasicAuthentication", true, "roundthecode");
		var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(authenticatedUser));

		return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(claimsPrincipal, Scheme.Name)));
	}
}

How to Configure Basic Authentication in ASP.NET Core

Now that we have the functionality created, it's time to configure our ASP.NET Core application so we can get Basic Authentication to work.

To do this, we need to make two changes in the Startup class.

Add Authentication Scheme

The first thing we need to do is to add the authentication scheme. To do this, we can add the scheme to the AuthenticationBuilder instance inside the ConfigureServices method.

The AddScheme method is what we use. This method allows us to add our BasicAuthenticationHandler as a generic method. As a result, we can hook this scheme against this handler.

In addition, we need to give the scheme a name. In this instance, we are going to call it BasicAuthentication.

// Startup.cs
public class Startup
{
	...

	// This method gets called by the runtime. Use this method to add services to the container.
	public void ConfigureServices(IServiceCollection services)
	{
		...
            services
                .AddAuthentication()
                .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", options => { });
	}

	...
}

Add Authorisation Policy

The other thing we need to do is to add an authorisation policy.

Now, when we created the BasicAuthorization attribute, we set a policy name of BasicAuthentication.

We need to make sure that when we add the policy, we give it the same name.

In addition, we need to make sure that for this policy to succeed, we need to have a authenticated user.

public class Startup
{
	...

	// This method gets called by the runtime. Use this method to add services to the container.
	public void ConfigureServices(IServiceCollection services)
	{
		...

		services.AddAuthorization(options =>
		{
			options.AddPolicy("BasicAuthentication", new AuthorizationPolicyBuilder("BasicAuthentication").RequireAuthenticatedUser().Build());
		});                       
	}

	...
}

Does the Basic Authentication Work When We Apply It?

Watch the video below to apply Basic authentication to an ASP.NET Core MVC application.

We use the [BasicAuthorization] attribute in an action from one of our controllers.

From there, we go ahead and test the functionality.

Using Basic Authentication When Generating an OAuth Bearer Token

We can use basic authentication when generating a JWT as an OAuth Bearer token.

This gives us some extra security when generating valid Bearer token when using OAuth security.

This is particularly useful for API's. Find out in Part 2 how to implement this which will be available on 23rd December.

Subscribe to our YouTube Channel

  • Free ASP.NET Core coding tutorial videos.
  • Implement a how-to guide on a topic related to ASP.NET Core.
  • Covers Blazor, Web API's, SQL Server, EF and many more...
Subscribe

Join our Discord Server

  • Can't get your ASP.NET Core application to work? Ask for help here!
  • Discussions with other ASP.NET Core developers.
  • General chat with the community.
Join
David Grace

David Grace

I am a .NET developer, building web applications in .NET Framework and .NET Core with a SQL Server database.

Some of the .NET packages I have used include Entity Framework and MVC.

I've also used many JavaScript frameworks such as React and jQuery, and have experience building CSS in SASS.

Twitter Feed