Authentication is the process or action of proving or showing something to be true, genuine, or valid. In order to access any secured resource over the internet/intranet, you have to provide the credential. It may be a username, password or secret key, etc.
What is Basic Authentication?
Basic authentication is a simple authentication scheme built into the HTTP protocol. The client sends HTTP requests with the Authorization
the header that contains the word Basic
followed by a space and a base64-encoded string username:password
.
Is Basic Auth Secure?
If you are using Basic authentication. then it’s highly recommended to host your application in the HTTPS environment. Because the username and password will be just converted to the base64 token. which can be tracked and decrypted easily.
We are going to implement the Basic Authentication in Asp.Net Core web API. Also, will have a demo, on how to access the web API secured by basic auth.
Let’s start building the project
Note: I am going to use Postman as a client for testing the API
I have created an Asp.Net core 2.0 project called RestApi.demo which will have one secure controller called EmployeeController.
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; namespace RestApi.Demo.Controllers { [Route("api/employee")] [ApiController] public class EmployeeController : ControllerBase { // GET: api/Employee [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } } }
As you can see in the above code snippet EmployeeControll class does not have an Authorize attribute. Also, it has only one method called Get which will be accessible through API/Employee.
Let’s run the project and see what we get in the postman response. As expected you will see the welcome message. Because we have not added any kind of authentication to our WebAPI project.
As you can, we could hit the controller and access the result without any issue.
Now, Try to put some authentication on our EmployeeeController
In order to secure your EmployeeController, you have to make a few changes in two places.
- You have to decorate the EmployeeController with Authorize attribute.
- you have to add an authentication module in your WebApi using startup.cs file.
- And, you have to specify which authentication scheme you are going to us
- Also, you have to provide the implementation of the BasicAuthentication middleware. Which will validate the incoming credential against your database or configuration.
Start with EmployeeController by adding the [Authorize] attribute.
using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace RestApi.Demo.Controllers { [Route("api/employee")] [ApiController] [Authorize] public class EmployeeController : ControllerBase { // GET: api/Employee [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } } }
Edit the Startup.cs file and method called ConfigureServices.
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("Basic"); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
As you can see in line no # we have added services.AddAuthentication(“Basic”) which will tell API that an authentication mechanism has been added.
Now, start making changes in the Configure method of a startup.cs file. Here we have to add the basic authentication along with the pipeline before the MVC. Which will validate the incoming credential against your configuration or database.
For demonstration purposes, I am using a hardcoded value. admin ad username and password.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseHttpsRedirection(); app.UseMiddleware<BasicAuthMiddleware>(new BasicAuthenticationOptions { Name = "admin", Password = "admin" }); app.UseMvc(); }
BasicAuthMiddleware.cs is the middleware class where we are going to validate the credential. So, please go through it carefully.
using Microsoft.AspNetCore.Http; using System; using System.Linq; using System.Net; using System.Security.Principal; using System.Threading.Tasks; namespace RestApi.Demo.Core { public class BasicAuthMiddleware { private readonly RequestDelegate _next; private readonly BasicAuthenticationOptions _options; public BasicAuthMiddleware(RequestDelegate next, BasicAuthenticationOptions options) { this._next = next; this._options = options ?? throw new ArgumentException("User info can't be null"); } public async Task Invoke(HttpContext context) { if (CheckIsValidRequest(context, out string username)) { var identity = new GenericIdentity(username); var principle = new GenericPrincipal(identity, null); context.User = principle; await this._next.Invoke(context); } else { context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; } } private bool CheckIsValidRequest(HttpContext context, out string username) { var basicAuthHeader = GetBasicAuthenticationHeaderValue(context); username = basicAuthHeader.UserName; return basicAuthHeader.IsValidBasicAuthenticationHeaderValue && basicAuthHeader.UserName == this._options.Name && basicAuthHeader.Password == this._options.Password; } private BasicAuthenticationHeaderValue GetBasicAuthenticationHeaderValue(HttpContext context) { var basicAuthenticationHeader = context.Request.Headers["Authorization"] .FirstOrDefault(header => header.StartsWith("Basic", StringComparison.OrdinalIgnoreCase)); var decodedHeader = new BasicAuthenticationHeaderValue(basicAuthenticationHeader); return decodedHeader; } } public class BasicAuthenticationOptions { public string Name { get; set; } public string Password { get; set; } } public class BasicAuthenticationHeaderValue { public BasicAuthenticationHeaderValue(string authenticationHeaderValue) { if (!string.IsNullOrWhiteSpace(authenticationHeaderValue)) { this._authenticationHeaderValue = authenticationHeaderValue; if (TryDecodeHeaderValue()) { ReadAuthenticationHeaderValue(); } } } private readonly string _authenticationHeaderValue; private string[] _splitDecodedCredentials; public bool IsValidBasicAuthenticationHeaderValue { get; private set; } public string UserName { get; private set; } public string Password { get; private set; } private bool TryDecodeHeaderValue() { const int headerSchemeLength = 6; if (this._authenticationHeaderValue.Length <= headerSchemeLength) { return false; } var encodedCredentials = this._authenticationHeaderValue.Substring(headerSchemeLength); try { var decodedCredentials = Convert.FromBase64String(encodedCredentials); this._splitDecodedCredentials = System.Text.Encoding.ASCII.GetString(decodedCredentials).Split(':'); return true; } catch (FormatException) { return false; } } private void ReadAuthenticationHeaderValue() { IsValidBasicAuthenticationHeaderValue = this._splitDecodedCredentials.Length == 2 && !string.IsNullOrWhiteSpace(this._splitDecodedCredentials[0]) && !string.IsNullOrWhiteSpace(this._splitDecodedCredentials[1]); if (IsValidBasicAuthenticationHeaderValue) { UserName = this._splitDecodedCredentials[0]; Password = this._splitDecodedCredentials[1]; } } } }
That’s it, we don’t have to make changes anywhere else to achieve the basic authentication in our web API project.
Now, we are all set up to make a secure API call using Basic authentication. Let’s try to execute the EmployeeController action method using Postman.
You have to configure the Basic authentication in your Postman application. Also, I have highlighted the options where you have to make changes.
Conclusion
So, in this article, we got the idea of basic authentication and how to implement that. Let us know in the below comments section if you find this article useful. Also, if you want me to update this article to validate the credential against a database or configuration.
Comments are closed.