Application security
.NET Core ASP.NET Core C# JWT Visual Studio

How to Retrieve User Context from JWT Bearer Tokens in .NET Core

Welcome to today’s post.

In today’s post I will be discussing how we can retrieve user details from JWT bearer tokens within a .NET Core Web API.

In a previous post I showed how we can retrieve user details from a JWT bearer token by decoding a token. However, this method relies on having to use the secret to decode the token.

At this point you would already be aware of how we encode and decode JWT tokens from an identity service and from a protected consuming web API. I will proceed to show how we setup the extensions in our .NET Core to allow us to obtain the Http Context and the JWT authorization token.

In ConfigureServices() make the following changes:

To enable JWT authentication services we are required to inject it as follows:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(..)

In our classes, to make use of the JWT Bearer authentication we will need the following namespace:

using Microsoft.AspNetCore.Authentication.JwtBearer;

And to utilize the token validation of signing keys we need to following namespace:

using Microsoft.IdentityModel.Tokens;

To enable HTTP context to be injected safely into our dependent controllers and services we use the HttpContextAccessor service as follows:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

In our classes, to use the HttpContextAccessor, we will need to use the namespace:

using Microsoft.AspNetCore.Http;

In Configure() make the following changes:

To enable the authentication of the token to be validated in the HTTP request header enable the following extension middleware:

app.UseAuthentication();

To enable authorization of methods and controllers in our API controller we enable the following extension middleware:

app.UseAuthorization();

In the above sequence, we must ensure the authentication is declared before authorization. The reason is the authentication of the user comes before they are authorized to call an API method that is protected with the [Authorize] attribute.

From this point on we will have the user identity and claims available in the HttpContext of the request header after we have run and executed one of our HTTP REST API methods successfully.

Assuming that the user roles are stored in the claims within:

Request.HttpContext.User.Claims

or

Request.HttpContext.User.Identity.Claims

In a routine debug of one of the API calls we can see the structure as shown:

From here we can implement a rudimentary service that retrieves both the username and claims which contain the roles the user is under:

using System;
using System.Collections.Generic;
using System.Linq;
using BookLoan.Catalog.API.Models.UserViewModels;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;

namespace BookLoan.Catalog.API.Services
{
    public class UserContextService: IUserContextService
    {
        private readonly HttpContext _context;

        public UserContextService(IHttpContextAccessor httpContextAccessor)
        {
            _context = httpContextAccessor.HttpContext;
        }

        public UserContextModel GetUserDetails()
        {
            var userContext = new UserContextModel();
            string userName = _context.Request.HttpContext.User.Identity.Name;
            List<Claim> claims = _context.Request.HttpContext.User.Claims.Where(
                c => c.Type == ClaimTypes.Role.ToString()).ToList();
            if ((claims == null) || (claims?.Count == 0))
                throw new Exception("Cannot retrieve user claims.");
            userContext.roles = new List<string>();
            userContext.userName = userName;

            foreach (Claim claim in claims)
            {
                userContext.roles.Add(claim.Value);
            }
            return userContext;
        }
	…
    }
}

From the above we add some additional methods to test role memberships:

 private bool IsMemberOfRole(string role)
 {
     return GetUserDetails().roles.Contains(role);
 }

 public bool IsAdminUser()
 {
     return IsMemberOfRole("Admin");
 }

public bool IsMemberUser()
{
    return IsMemberOfRole("Member");
}

public bool IsGuestUser()
{
    return IsMemberOfRole("Guest");
}

To inject the user context service we use the following in ConfigureServices():

services.AddTransient<IUserContextService, UserContextService>();

Once this is all setup, we have quite a modular, cleaner consumption of the user context properties which can allow us to use this information to provide the testing of user role memberships within our service classes.

For example, we can make the logical tests of role membership within service methods. An example of one of these is shown below:

public async Task SaveBook(BookViewModel vm)
{
   if (!this._userContextService.IsAdminUser())
      throw new Exception("Only Admin users can create new books!");

   _db.Add(vm);
   vm.DateCreated = DateTime.Now;
	…
}

We have seen from the above how to extract the following useful properties from a user context that contains a bearer token in .NET Core:

  1. User login name
  2. User claims
  3. User roles

We also saw how to encapsulate these user properties and roles within an application.

That is all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial