Add Azure AD Authentication and Retrieve Current User Details in .NET 7 Minimal API

Praveen Desai
Version 1
Published in
4 min readMar 17, 2023
Photo by Ed Hardie on Unsplash

Implementing authentication in the application is critical in ensuring the security and integrity of the application. Also, gaining trust from users and retrieving user details from the request object is needed as part of the requirement in most cases.

Let us discuss how to add Azure AD authentication and retrieve current user details like username, user-id, IsAuthenticated and user email details in .NET 7 minimal API.

This article assumes you have a minimal API created using Clean Architecture on .NET 7 Framework.

Azure AD Authentication:
Azure AD authentication provides several benefits like centralised identity management, multi-factor authentication, and integration with other Microsoft Services, and it uses industry standard-based protocols such as OAuth 2.0 and OpenID connect.

To add Azure Ad authentication, follow the below steps:

  1. Register an application with Azure Ad to authenticate users and access protected resources. This involves creating an application registration in the Azure portal and configuring its authentication settings.
    Follow this link for more information.
  2. Once the registration of your application is completed, configure the application to use Azure AD authentication. This typically involves adding appropriate authentication middleware to your application and configuring the middleware with appropriate settings for your Azure AD tenant and application.

a. Install the below packages in your API layer.

Microsoft.AspNetCore.Authentication.JwtBearer;

Microsoft.Identity.Web;

b. Add the following code to configure Azure AD authentication in StartUp.cs file.

This code configures the authentication middleware to use the JWT bearer authentication scheme and sets the authentication options from the Azure AD configuration section in the appsettings.json file.

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication();
app.UseAuthorization();
}

c. Add the following configuration to your appsettings.json file to configure Azure AD:

{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "YOUR_CLIENT_ID",
"TenantId": "YOUR_TENANT_ID"
}
}

d. Now we are ready to add authentication on each minimal API endpoint.

Endpoints are defined inside the DefineEndpoints method.

public void DefineEndpoints(WebApplication app)
{

var getCurrenciesEndpoint = app.MapGet("/currencies", GetCurrencies)
.WithName("Get All Currencies")
.WithDisplayName("Get All Currencies")
.WithTags("Currencies Endpoints");

getCurrenciesEndpoint.RequireAuthorization();
}

When you call RequireAuthorization() on an endpoint or a route, it ensures that the user must be authenticated before accessing that endpoint.

3. Test the authentication flow using the swagger (OpenAPI Service) or Postman to ensure that users can authenticate and access protected resources successfully.

Now let us move on to the second topic, to retrieve current user details in ASP.NET Core Minimal API.

Retrieve current user details:

In a minimal API, the DefineEndpoints method defines the API endpoints. The HttpContext is unavailable in this method, so you cannot access the User property directly.

The IHttpContextAccessor interface provides access to the current HttpContext instance for the current request in an ASP.NET Core application. This interface can access and modify various properties of the HttpContext, such as the request and response objects, user identity, session data, and more.

To access the User property in the DefineEndpoints method, you can inject the IHttpContextAccessor service and use it to access the current HttpContext.

Note that injecting the IHttpContextAccessor service directly into the endpoint logic can result in thread-safety issues and should be used cautiously. It is recommended to use the HttpContext in the controller action methods or middleware components where possible.

Instead of working with IHttpContextAccessorService, we can create a CurrentUserService class to achieve our needs.

Follow below steps to create custom Service,

  1. create an Interface IcurrentUserService with below definition,
public interface ICurrentUserService
{
public string UserId { get; }

public string UserName { get; }

public string UserEmail { get; }
}

2. Create a class which implements Interface ICurrentUserService.

public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;

public CurrentUserService(IHttpContextAccessor httpContextAccessor)
=> _httpContextAccessor = httpContextAccessor;

public bool IsAuthenticated
=> _httpContextAccessor.HttpContext?.User.Identity?.IsAuthenticated
?? false;

public string UserId
=> _httpContextAccessor.HttpContext?.User?.FindFirstValue(Claims.Oid)
?? _httpContextAccessor.HttpContext?.User?.FindFirstValue(Claims.Sub)
?? string.Empty;

public string UserName
=> _httpContextAccessor.HttpContext?.User?.FindFirstValue(Claims.Name)
?? string.Empty;
public string UserEmail
=> ((System.Security.Claims.ClaimsIdentity)_httpContextAccessor.HttpContext?.User?.Identity).Claims.ElementAt(11).Value
?? string.Empty;

}

3.Register this CurrentUserService with dependency injection container as below.

public IServiceCollection ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddHealthChecks();
services.AddCors();
services.AddHttpContextAccessor();
services.AddScoped<ICurrentUserService, CurrentUserService>();

return services;
}the AddHttpContextAccessor method is used to register the IHttpContextAccessor service in the dependency injection container.

The AddHttpContextAccessor method is used to register the IHttpContextAccessor service in the dependency injection container.

4. Services are added to the request pipeline by getting the list of Assemblies and creating an instance of those with the help of the AddService Method defined in ConfigurationExtetnsion Class.

public static void AddServices(this WebApplicationBuilder builder, params Assembly[] assemblies)
{
assemblies.SelectMany(assembly => assembly.ExportedTypes
.Where(x =>
typeof(IServicesConfiguration).IsAssignableFrom(x)
&& !x.IsInterface
&& !x.IsAbstract)
.Select(Activator.CreateInstance)
.Cast<IServicesConfiguration>())
.ToList()
.ForEach(sc =>
sc.ConfigureServices(builder.Services, builder.Configuration));

}

5. Now ICurrentUserService is ready to be injected into other classes.

The below code snippet in the Application layer shows how ICurrentUserService is injected into MediatR pattern handler and is used to retrieve user details.

public class CreateCurrencyQueryHandler : IRequestHandler<CreateCurrencyQuery, RequestResult<Unit>>
{


private readonly ICurrentUserService _currentUserService;

public CreateCurrencyQueryHandler(ICurrentUserService currentUserService)
{

_currentUserService = currentUserService;
}

public async Task<RequestResult<Unit>> Handle(CreateCurrencyQuery request, CancellationToken cancellationToken)
{

var userName = _currentUserService.UserName;

//
// some code
//

return RequestResult<Unit>.Success(Unit.Value);
}
}

We have now seen how to add Azure AD authentication and retrieve current user details in .NET 7 minimal API.

Happy Learning:)

About the author

Praveen Desai is a .Net Developer here at Version 1.

--

--