3

I'm developing a multi-tenant application with asp.net core 3.1 as the backend. I used JWT to authenticate users. I'm passing the tenantId along with the http request and I would like to validate JWT against tenantIds. To do this, I must pass the tenantIds to JwtBearerOptions.ValidAudience at each client request.

I set options at startup as follows...

public void ConfigureServices(IServiceCollection services){
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(configureOptions =>
        {
            configureOptions.ClaimsIssuer = jwtOptions["Issuer"];
            configureOptions.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidIssuer = jwtOptions["Issuer"],
                ValidAudience = tenantId,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = accessKey,
                RequireExpirationTime = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
        });
}

Please note that I don't want to pass all tenantIds to ValidateAudiences because each tenant should receive an unique token. e.g. I don't want tenant X's token works for tenant Y.

How do I achieve this?

Thanks in advance!

Nan Yu
  • 26,101
  • 9
  • 68
  • 148
ecasper
  • 489
  • 1
  • 10
  • 30

2 Answers2

2

I'm not sure why you want to set tenant id as Audience , but you can use custom audience validator to implement the logic in TokenValidationParameters :

AudienceValidator = (audiences, securityToken, validationParameters) =>
{
    //return true/false based on your requirement 
    return true;
},
Nan Yu
  • 26,101
  • 9
  • 68
  • 148
  • Thanks, I’m aware of the AudienceValidator delegate but I’m looking for a way to reinstate TokenValidateParameters at every client request. – ecasper May 14 '20 at 09:30
  • @ecasper I would suggest that you use the `AudienceValidator` instead of reinstantiating the tokenvalidation parameters as that would not be a best practice, the `AudienceValidator` is the one that is responsible for taking the tenantId from the header and validating against your source of truth, The pipeline construction should not be varying for each request, but the handlers should take off the load and get the job done. HTH – Saravanan May 17 '20 at 05:18
1

I ended up using below for validating tenderid and I'm quite happy with the outcome. please let me know if there are drawbacks to approch below, thanks!

                ValidAudiences = tenants.Value.Select(x=>x.TenantId).ToList(),
                IssuerSigningKeyResolver = (string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) =>
                {
                    var tenant = tenants.Value.Where(t => t.TenantId == kid).FirstOrDefault();
                    List<SecurityKey> keys = new List<SecurityKey>();
                    if (tenant != null && kid == tenantsResolver.GetCurrentTenantId())
                    {
                        var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tenant.SecretKey));
                        keys.Add(signingKey);
                    }
                    return keys;
                }
ecasper
  • 489
  • 1
  • 10
  • 30