Add Auth Middleware
Implement auth middleware to ensure only authenticated users access sensitive APIs.
Now that your application is properly managing sessions, let's add middleware to verify that only users with valid sessions can access protected backend APIs.
Create Auth Middleware
To verify that frontend requests to your Session endpoint have an authenticated session, you can create an auth middleware that checks for a valid session cookie. Below is an example of an auth middleware function:
// AuthMiddleware.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Wristband.AspNet.Auth;
public class AuthMiddleware
{
private readonly RequestDelegate _next;
public AuthMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext context, IWristbandAuthService wristbandAuth)
{
// Only verify the session for endpoints with the RequireWristbandAuth attribute.
// This allows for selectively choosing which endpoints require authentication.
if (context.GetEndpoint()?.Metadata.GetMetadata<RequireWristbandAuth>() == null)
{
await _next(context);
return;
}
// Verify that the request contained a valid session cookie.
if (!await IsAuthenticated(context))
{
// If the request doesn't have a valid session cookie return a 401 response.
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
// Save the session in order to "touch" it and extend the session expiration window.
await context.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
context.User,
new AuthenticationProperties { IsPersistent = true });
await _next(context);
}
private async Task<bool> IsAuthenticated(HttpContext context)
{
var authResult = await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return authResult.Succeeded && authResult.Principal != null;
}
}
Now configure your auth middleware in Program.cs
. Make sure to place the auth middleware after UseAuthentication
but before any protected routes are declared.
// Program.cs
...
app.UseAuthentication();
app.UseMiddleware<AuthMiddleware>(); // Enables your auth middleware.
// API routes
app.MapAuthEndpoints();
...
Enable Auth Middleware For Session Endpoint
To enable the auth middleware for the Session Endpoint, we need to add the RequireWristbandAuth
attribute to its metadata. Also, since the session cookie is being validated by the middleware now, we can remove the logic from the Session Endpoint that was checking to see if the user was authenticated. The Session Endpoint implementation should now look like the following example:
// AuthRoutes.cs
using System.Security.Claims;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Wristband.AspNet.Auth;
...
// Session Endpoint
app.MapGet("/session", (HttpContext httpContext) =>
{
var user = httpContext.User;
//
// This check can be removed since the session is now validated in
// the auth middleware
//
// if (user?.Identity == null || !user.Identity.IsAuthenticated)
// {
// return Results.Unauthorized();
// }
//
return Results.Ok(new
{
userId = user.FindFirst("userId")?.Value ?? string.Empty,
tenantId = user.FindFirst("tenantId")?.Value ?? string.Empty
});
})
.WithMetadata(new RequireWristbandAuth()); // Add RequiresWristbandAuth metadata to protect the session endpoint with the auth middleware.
...
Enable Auth Middleware For Your Application's Protected Endpoints
Make sure to add the RequireWristbandAuth
attribute to any other endpoints in your application that require an authenticated user session. Below are some examples showing how to protect your endpoints with the RequireWristbandAuth
attribute.
// Attribute-based approach
app.MapGet("/protected-api", [RequireWristbandAuth] () => Results.Ok("This is a protected endpoint"));
// Metadata-based approach
app.MapGet("/protected-api", () => Results.Ok("This is a protected endpoint"))
.WithMetadata(new RequireWristbandAuth());
Does The Auth Middleware Need to be Applied to The Auth Endpoints?
The Login, Callback, and Logout Endpoints are meant to be accessed by unauthenticated users, so you don't need to add the
RequireWristbandAuth
attribute to them.
Updated 14 days ago
Now that your server endpoints are protected, let's update the frontend code to handle unauthorized error responses.