Search code examples
c#asp.netauthenticationjwtasp.net-identity

How can I use a service to configure another service?


I'm configurating a AuthenticationService in my application, with JwtBearer .

I abstracted the JWT configuration to a service, to use it throughout the application. So, that's my code.

builder.Services.AddSingleton<JWTService>();

builder.Services.AddAuthorization(options =>
{   
    options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession"));
});
builder.Services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = ...;
});
public class JWTService
{
    private IConfiguration _configuration;

    public JWTService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public TokenValidationParameters Config()
    {
        return new TokenValidationParameters()
        {
            ValidateActor = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ClockSkew = TimeSpan.Zero,
            ValidAudience = _configuration["JwtBearerTokenSettings:Audience"],
            ValidIssuer = _configuration["JwtBearerTokenSettings:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtBearerTokenSettings:SecretKey"]))
        };
    }
}

So, how can I get the JWTService to use it as a parameter of AddJwtBearer, with Config method? I managed to do this using builder.Services.BuildServiceProvider().GetServices, but I read that this is not recommended. Is there another way?


Solution

  • You should be able to add a delegate which will be called when the service is resolved which can then also have other services you need, like IConfiguration provided to it so that you can dynamically configure the options before they are used:

    builder.Services.AddAuthorization(options =>
    {
        options.AddPolicy("UserPolicy", p => p.RequireAuthenticatedUser().RequireClaim("Profession"));
    });
    builder.Services.AddAuthentication(x =>
    {
        x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer();
    
    builder.Services
        .AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
        .Configure<IConfiguration>((options, configuration) =>
        {
            options.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidateActor = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ClockSkew = TimeSpan.Zero,
                ValidAudience = configuration["JwtBearerTokenSettings:Audience"],
                ValidIssuer = configuration["JwtBearerTokenSettings:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtBearerTokenSettings:SecretKey"])),
            };
        });