Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API Authentication with multi-tenant data access

I am not sure if I used the correct title but I was unable to think of a better way to describe it. It could be more of a design question.

I have a multi-tenant DB where one user can belong to one or more entities. I authenticate the user with his/her credentials by calling the /token endpoint.

After I receive a token I call my own end point (using the token) to get the list of available entities for this user and then allow this user to set his current entity in a memory cache. I then use this in memory cache to look up the entity/tenant ID for all following requests to know which entity/tenant the user is "logged into" when calling the DB.

Ideally I would like to eliminate the need for the memory cache in order to make my application more stateless by including the entity/tenant ID as a claim in the token but I only know this ID after the user has authenticated and selected his/her entity. I obviously can't change or add to the claims after the token is issued but is there an alternative design to implement this kind of behavior?

I considered possibly using a sub domain per tenant but technically this is more difficult to setup and maintain. I also considered prompting the user to enter the entity he/she wishes to log in to as free text with their credentials but this isn't ideal.

Has anyone faced this challenge before?

like image 791
Ross Avatar asked Apr 12 '16 20:04

Ross


1 Answers

I agree with you in the fact that the tenant selection must be done in a stateless way, in order to avoid stateful interaction in a REST-based architecture. The caching approach may lead to many pitfalls and introduces a strong dependency on a session-based interaction.

I can think of two main options to make the tenant selection stateless:

  1. URI based selection: you could add to you API a tenant parameter, shared between all your controllers. A mapping similar to this: api/{tenantId}/{controller}/{id} could allow you to switch between tenants in a simple way client-side. This can be done using both the convention-based routing:

    routes.MapHttpRoute(
        name: "API Default",
        routeTemplate: "api/{tenantId}/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
    

    Or the attribute-based routing, using RoutePrefixAttribute on your controllers:

    [RoutePrefix("api/{tenantId}/myentities")]
    public class EntityController : ApiController
    {
        [Route("")]
        public IHttpActionResult GetAllEntities(string tenantId)
        {
            //...
    
  2. Header based selection: you could consider adding a custom HTTP header, which will contain information about the selected tenant: e.g. X-Tenant-Selection: TenantId, then you could read this Header inside a custom Filter, or in a OwinMiddleware executed before Web API, and set a context variable (or even a user claim that will last for the current request) to be used inside your controllers.

Of course in both scenarios you have to validate that the current user can access to the selected tenant before returning data.

Frankly I would exclude the possibility to include the tenantId inside the access token, and the sub-domain approach appears too complicated to me.

like image 149
Federico Dipuma Avatar answered Sep 21 '22 13:09

Federico Dipuma