Implementing Windows Authentication in .NET Core Web API (short guide with examples)
Use case:
We need to implement simple Windows authentication for an intranet ASP.NET CORE WEB API application which should authorize users by verifying user details in a custom database.
What is Windows Authentication?
Windows Authentication, also known as Integrated Windows Authentication, is a secure authentication mechanism used in Microsoft Windows environments. It enables users to access network resources, applications, and services by authenticating with their Windows credentials, such as username and password, without the need for additional login prompts.
Windows Authentication is highly secure and well-suited for corporate environments. This mechanism is commonly used in Windows-based web applications, intranet sites, and services that require robust identity verification within Windows domains.
Configuring Windows Authentication in the program.cs (startup.cs).
To configure our application to use authentication and authorization, include AddAuthentication
and AddAuthorization
as shown below. Next, add UseAuthentication
and UseAuthorization
enables the same.
var builder = WebApplication.CreateBuilder(args);
...
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
var app = builder.Build();
...
app.UseAuthentication();
app.UseAuthorization();
Enabling Windows Authentication in the launchSettings.json file.
To instruct the IIS server, we need to configure launchSettings.json
by adding windowsAuthentication
as true
and anonymousAuthentication
as false
.
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:57281",
"sslPort": 0
}
}
Create Custom Authorize attribute
To authorize logged-in users, we need to check the user's details in the database and then allow/restrict access to them.
The bellow code will do the following things (refer OnAuthorization
block)
Skip the authorization check if
AllowAnonymous
is enabledGet the logged-in user details using
context.HttpContext.User.Identity?.Name
Fetch the user's role details from the database
Authorize only
If Role is not passed but the user exists in the database
If Role is passed and the user exists in the database with the expected role
Return Unauthorized - Either the user does not exist or does not have an expected role in the database
public class CustomRoleAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public string[] Role { get; }
public CustomRoleAuthorizationAttribute(string role)
{
Role = string.IsNullOrWhiteSpace(role) ? Array.Empty<string>() : role.Trim().Split(",");
}
public CustomRoleAuthorizationAttribute()
{
Role = Array.Empty<string>();
}
public void OnAuthorization(AuthorizationFilterContext context)
{
// skip authorization if action is decorated with [AllowAnonymous] attribute
var allowAnonymous = context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any();
if (allowAnonymous)
return;
// authorization
var user = context.HttpContext.User.Identity?.Name;
//TODO - get user and role from database (userDb)
var userFromDb = new UserWithRole() { User = "Raja", Role = "Admin" };
var authorized = userFromDb != null && !string.IsNullOrWhiteSpace(userFromDb.User) && (Role == Array.Empty<string>() || Role.Contains(userFromDb.Role));
if (string.IsNullOrWhiteSpace(user) || !authorized)
{
context.Result = new JsonResult(new { message = $"Unauthorized user {user}" }) { StatusCode = StatusCodes.Status401Unauthorized };
}
}
}
Securing your API routes with [Authorize] attributes
From the example below, if we mention [CustomRoleAuthorization("Admin")]
then it will check if the logged-in user exists in the database with the "Admin" role.
If we mention [CustomRoleAuthorization]
, it will check that only the user exists in the database and allow the login.
[CustomRoleAuthorization("Admin")]
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
Test the authorization
Run the application and call GetWeatherForecast
API from the browser. It will check whether the logged-in user exists in the database with the "Admin" role.
This is a simple solution to authenticate users by integrating Windows authentication and authorization by verifying user details in a custom database