I am using JWT based authentication in my .net core 2.1 web site. Currently this works fine. Now, I have to make one API multi-tenant and each tenant will have it's own secret key. The tenant Id will be passed as parameter to the API.
[Authorize]
[HttpGet("tenant/{id}")]
public async Task<IActionResult> GetInfo(string id)
{
}
Each tenant will sign the JWT and will add to Authorization header. I am not able to think of a way to change IssuerSigningKey based on the parameter. I tried following:
Validating the JWT inside the API by making it [AllowAonymus
]. This works but I have end up writing all the JWT validating code.
Implementing ISecurityTokenValidator
I can implement ISecurityTokenValidator
to validate the token and using this in startup configuration something like this:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new JWTSecurityTokenValidator());
});
And implemented my own class to validate the token.
public class JWTSecurityTokenValidator : ISecurityTokenValidator
{
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
// Implement the logic
}
}
But again I end up doing heavy lifting. Also, I am not able to access the parameter "tenantId" in the ValidateToken.
3.Using IssuerSigningKeyResolver
:
I can implement a delegate:
IEnumerable<SecurityKey> IssuerSigningKeyResolver(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)
Again I don't's have access to the "tenantId" parameter to choose the appropriate key.
Is there elegant solution to choosing IssuerSigningKey
based on the parameter so that I don't need to write my own logic to validate JWT? Or only option is to go with first option?
You can use DI to pass IHttpContextAccessor
instance into your JWTSecurityTokenValidator
and get value of IHttpContextAccessor.HttpContext
property.
From .Net Core 2.1 , you can register using extension :
services.AddHttpContextAccessor();
Then in your custom JWTSecurityTokenValidator
, modify to inject the IHttpContextAccessor
:
private readonly IHttpContextAccessor _httpContextAccessor;
public JWTSecurityTokenValidator(IHttpContextAccessor httpContextAccessor) {
_httpContextAccessor = httpContextAccessor;
}
Modify the registration in Startup.cs
:
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new JWTSecurityTokenValidator(services.BuildServiceProvider().GetService<IHttpContextAccessor>()));
So that in ValidateToken
method ,you can read the parameter from _httpContextAccessor.HttpContext
, according to how you pass the parameter , read it from query string or path :
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
var xx = _httpContextAccessor.HttpContext.Request;
........
}