Search code examples
c#single-page-applicationasp.net-core-webapirestful-authenticationmsal.js

Proper place to validate issuer for multi-tenant .Net Core Web API app


I'm developing a multi-tenant SPA application that calls a back-end .Net Core Web API for data. The front end UI will use MSAL and Microsoft's v2 common endpoint for authenticating the user against AAD and obtaining an id and access token.

In my Web API, I want to validate the issuer, but as noted here, using the common endpoint provides metadata that makes the normal issuer validation un-useable.

I've seen references to a couple places where it may be possible to override or customize token validation, but I'm not sure which is preferred or if either of these methods causes undesired side effects.

One method uses the Events of the JwtBearer options: options.Events.TokenValidated and the other uses the IssuerValidator delegate of the TokenValidationParameters.

I don't want to have to write any token validation logic other than just ensuring the issuer exists in my database of verified issuers. Should that logic go in the IssuerValidator or TokenValidated?

My current code looks like this (currently set up for single tenant)

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
   .AddJwtBearer(options =>
    {
       options.Authority = "https://myauthority.com";
       options.Audience = "https://myaudience.com/api/v1";
       options.TokenValidationParameters = new TokenValidationParameters
       {  
          ValidateIssuer = true,
          ValidIssuer = "myauthority.com",
          ValidateAudience = true,
          ValidAudience = "https://myaudience.com",
          ValidateLifetime = true,
          ValidateIssuerSigningKey = true,
        };
    });

One of the issues I see with using IssuerValidator is that there does not appear to be a way to inject or pass in a reference to a dbContext needed to be able to look up a tenant id in a database.

Has anyone tackled this or done something similar?


Solution

  • You can check that in OnTokenValidated event , to access the database context , you can try :

     options.Events.OnTokenValidated = async (context) =>
       {
    
    
           var dbContext = context.HttpContext.RequestServices.GetRequiredService<BloggingContext>();
           var blogs = await dbContext.Blogs.ToListAsync();
    
           if (!true)
           {
               throw new SecurityTokenValidationException($"Tenant xxxxx is not registered");
           }
    
       };