.NET

Authentication in a microservices architecture (.net)

When you want to decentralize your application with independently deployable services you would probably design your software applications in a Microservice Architecture style.

While there is no “best practice” or pattern to follow, you will most likely already have several projects running that would benefit from being smaller endpoints totally independent. Having a HTTP API application as a suite of small services will get you faster to market, give each developer in your team an ownership and do changes to small parts of your application fast.

In this post I will show you one approach for handling Authentication and Authorization for each small service. This is one of many ways, and I suppose the most common way is to have one or more endpoints as a gateway to all your small services and let that handle authentication.

In this post I will show you have to have one endpoint for authentication with OWIN, and store the user information for a given time in some storage. I use Redis Cache for storing key pair values, but you can use whatever you want.

You can find the sample project here.

These are the steps:

1. Override the TokenEndpointResponse on OWIN OAuth Authorization ServerProvider

We need to make sure we store the users token and userId when the user logs on. This way we can make sure that the user is authenticated and we can also grab the userId for logging or role management and so on. Make sure you update all your NuGet packages for this project.

public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
        {
            var theToken = context.AccessToken;
            var theClaims = context.Identity.Claims;
            return base.TokenEndpointResponse(context);
        }

2. Save the Token and the UserId in some storage.

I recommend using Redis on Azure, you can read this post to see how easy that is to set up, but for this sample I will use a simple json file like this:

 

public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
        {
            var dataFile = "c:\\temp\\accesstoken.txt";
            TokenStore data = new TokenStore() { token = context.AccessToken, UserId = context.Identity.Claims.Last().Value };
            File.WriteAllText(@dataFile, JsonConvert.SerializeObject(data));
            return base.TokenEndpointResponse(context);
        }

 

At this point you are done with the implement an OAuth 2.0 Authorization Server using OWIN OAuth middleware and saving your token and user information in some cache store. The only thing left now is to read that cache store data from all your Microservices that needs authorization.

These are the steps:

1. Grab the Token from the HttpActionContext

var token = ActionContext.Request.Headers.Authorization.Parameter;

2. Compare that with the token in your token store cache

// GET: api/Test
public string Get()
  {
   var token = ActionContext.Request.Headers.Authorization.Parameter;
   var dataFile = "c:\\temp\\accesstoken.txt";
   var data = File.ReadAllText(@dataFile);
   var response = JsonConvert.DeserializeObject<TokenStore>(data);
     if (response.token == token)
        {
           return response.UserId;
        }
     return null;
   }

What you should do is create a Custom Authorize Attribute so you can add attributes to the contracts you want to authenticate. This is the code:

TestController.cs

public class TestController : ApiController
    {
      [CustomAuthorize]
        public string Get()
        {
            return "test";
        }
    }

Authenticate.cs

public class Authenticate
    {
        public static bool Auth(string Token)
        {
            var dataFile = "c:\\temp\\accesstoken.txt";
            var data = File.ReadAllText(@dataFile);
            var response = JsonConvert.DeserializeObject<TokenStore>(data);
            if (response.token == Token)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

CustomAuthorizeAttribute.cs

public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            if (AuthorizeRequest(actionContext))
            {
                return;
            }
            HandleUnauthorizedRequest(actionContext);
        }


        protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            //Code to handle unauthorized request
            HttpContext.Current.Response.AddHeader("AuthenticationStatus", "NotAuthorized");
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
            return;
        }

        private bool AuthorizeRequest(System.Web.Http.Controllers.HttpActionContext actionContext)

        {
            var token = actionContext.Request.Headers.Authorization.Parameter;
            return Authenticate.Auth(token);
        }
    }

Thanks for reading.