Basic Authentication in ASP.NET Core
By FoxLearn 2/17/2025 9:47:22 AM 32
What is Basic Authentication?
To fully understand Basic Authentication, it’s important to know the difference between Authentication and Authorization:
- Authentication verifies the identity of a user (typically by username and password).
- Authorization ensures that an authenticated user has the necessary permissions to access certain resources.
Basic Authentication involves sending the user's credentials (username and password) encoded in Base64 format in the HTTP header. The server then decodes the credentials and validates them against stored values.
How Does Basic Authentication Work?
Let’s break down how Basic Authentication operates:
- The client sends a request to the server without any credentials.
- The server responds with a
401 Unauthorized
status code and indicates that Basic Authentication is required. - The client sends another request, this time with the credentials encoded in the
Authorization
header. - The server decodes the credentials, validates them, and if they match, it responds with a
200 OK
status and the requested data.
Advantages of Basic Authentication
- Simplicity: Basic Authentication is easy to understand and implement.
- Universal Support: Most HTTP clients and browsers support it.
- Stateless: It doesn’t require session storage, making it scalable.
Implementing Basic Authentication in ASP.NET Core Web API
We will now go through the steps to create a simple Web API and implement Basic Authentication.
Step 1: Create a Class Library Project (Customer.Domain
)
Start by creating a class library project named Customer.Domain
.
Step 2: Add a Customer
Model
In the Models
folder, create a Customer.cs
class:
namespace Customer.Domain.Models { public class Customer { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string UserName { get; set; } public string Password { get; set; } } }
Step 3: Create Customer.Application
Layer
Now, create a layer called Customer.Application
to handle the business logic. Inside this layer, create Repository
and Services
folders.
Step 4: Implement Repositories and Services
In the Repository
folder, create an interface ICustomerRepository.cs
:
namespace Customer.Application.Repository { public interface ICustomerRepository { Task<Customer.Domain.Models.Customer?> ValidateCustomer(string username, string password); Task<List<Customer.Domain.Models.Customer>> GetAllCustomers(); Task<Customer.Domain.Models.Customer> GetCustomerById(int id); } }
In the Services
folder, create an interface ICustomerService.cs
:
namespace Customer.Application.Services { public interface ICustomerService { Task<Customer.Domain.Models.Customer?> ValidateCustomer(string username, string password); Task<List<Customer.Domain.Models.Customer>> GetAllCustomers(); Task<Customer.Domain.Models.Customer> GetCustomerById(int id); } }
Next, implement the service:
namespace Customer.Application.Services { public class CustomerService : ICustomerService { private readonly ICustomerRepository _customerRepository; public CustomerService(ICustomerRepository customerRepository) { _customerRepository = customerRepository; } public Task<List<Customer.Domain.Models.Customer>> GetAllCustomers() => _customerRepository.GetAllCustomers(); public Task<Customer.Domain.Models.Customer> GetCustomerById(int id) => _customerRepository.GetCustomerById(id); public Task<Customer.Domain.Models.Customer?> ValidateCustomer(string username, string password) => _customerRepository.ValidateCustomer(username, password); } }
Step 5: Add References to Projects
Add references to Customer.Domain
in Customer.Application
.
Step 6: Create Customer.Infrastructure
Layer
Create a new layer called Customer.Infrastructure
to interact with the data. This layer will contain the repository for fetching customer data.
Step 7: Implement Repository
Inside the Customer.Infrastructure.Repository
folder, create the CustomerRepository.cs
file:
namespace Customer.Infrastructure.Repository { public class CustomerRepository : ICustomerRepository { List<Customer.Domain.Models.Customer> customers = new List<Customer.Domain.Models.Customer> { new Customer.Domain.Models.Customer { Id = 1, Name = "John Doe", Email = "[email protected]", UserName = "john", Password = "Password123" }, new Customer.Domain.Models.Customer { Id = 2, Name = "Jane Smith", Email = "[email protected]", UserName = "jane", Password = "Password456" } }; public async Task<List<Customer.Domain.Models.Customer>> GetAllCustomers() => customers.ToList(); public async Task<Customer.Domain.Models.Customer> GetCustomerById(int id) => customers.FirstOrDefault(c => c.Id == id); public async Task<Customer.Domain.Models.Customer?> ValidateCustomer(string username, string password) => customers.FirstOrDefault(c => c.UserName == username && c.Password == password); } }
Step 8: Create Web API Project
Create a new ASP.NET Core Web API project called CustomerApi
. Add references to Customer.Domain
, Customer.Application
, and Customer.Infrastructure
.
Step 9: Implement Basic Authentication Handler
In the CustomerApi
project, create a BasicAuthenticationHandler.cs
to handle authentication:
using Customer.Application.Repository; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; using System.Net.Http.Headers; using System.Security.Claims; using System.Text; namespace CustomerApi.Authentication { public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> { private readonly ICustomerRepository _customerRepository; public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> optionsMonitor, ILoggerFactory loggerFactory, ICustomerRepository customerRepository) : base(optionsMonitor, loggerFactory) { _customerRepository = customerRepository; } protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.ContainsKey("Authorization")) return AuthenticateResult.Fail("Missing Authorization Header"); var authenticationHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationHeader.Parameter)).Split(':', 2); if (credentials.Length != 2) return AuthenticateResult.Fail("Invalid Header Content"); var user = await _customerRepository.ValidateCustomer(credentials[0], credentials[1]); if (user == null) return AuthenticateResult.Fail("Invalid Customer"); var claims = new[] { new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), new Claim(ClaimTypes.Name, user.Name), }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); } } }
Step 10: Register the Authentication Handler
In Program.cs
, register the BasicAuthenticationHandler
and services:
builder.Services.AddAuthentication("BasicAuthentication") .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", options => { }); builder.Services.AddSingleton<ICustomerRepository, CustomerRepository>(); builder.Services.AddSingleton<ICustomerService, CustomerService>();
Step 11: Create Customer Controller
Now, create the CustomerController.cs
to manage customer-related API endpoints:
using Microsoft.AspNetCore.Mvc; namespace CustomerApi.Controllers { [Authorize(AuthenticationSchemes = "BasicAuthentication")] [ApiController] [Route("[controller]")] public class CustomerController : ControllerBase { private readonly ICustomerService _customerService; public CustomerController(ICustomerService customerService) { _customerService = customerService; } [HttpGet] public async Task<ActionResult<List<Customer.Domain.Models.Customer>>> GetCustomers() => await _customerService.GetAllCustomers(); } }
Step 12: Run and Test the Application
Run the application and use Postman to send requests. If the credentials are missing or incorrect, the server will respond with 401 Unauthorized
. Upon providing valid credentials, the server will return 200 OK
with the requested data.
You have successfully implemented Basic Authentication in an ASP.NET Core Web API. This method provides an easy and straightforward way to authenticate users. In future articles, we will explore more advanced authentication mechanisms, such as token-based authentication or role-based access control.
- How to Implement Stripe Payment Gateway in ASP.NET Core
- Comparing ASP.NET SOAP Services and Core APIs
- How to fix System.InvalidOperationException: Scheme already exists: Identity.Application
- Two-Factor Authentication with Google Authenticator in ASP.NET Core
- Implementing Passkeys to ASP.NET Core Application
- How to Implement Passkey Authentication in ASP.NET Core
- Implementing Google Authentication in the Blazor WebAssembly App
- How to Add a custom InputFormatter in ASP.NET Core