Get ServiceProvider inside AddOpenIdConnect without BuildServiceProvider()
Asked Answered
L

2

7

Is there a good way to get the ServiceProvider in the AddOpenIdConnect, or configure the ClientSecret later where we have the DI container fully setup? (e.g. in Configure(IApplicationBuilder app))

We're getting the client secret from somewhere else and we like to use DI for that.

Currently we do this, but I really like to remove services.BuildServiceProvider()

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddOpenIdConnect(AuthenticationScheme, options =>
    {
        ServiceProvider serviceProvider = services.BuildServiceProvider(); // we like to prevent this
        options.ClientSecret = serviceProvider.GetRequiredService<ISecretRetriever>().GetClientSecret();

Notes

For events like OnValidatePrincipal we could get it from CookieValidatePrincipalContext.HttpContext.RequestServices

Using services.BuildServiceProvider() will give this warning:

warning "Calling 'BuildServiceProvider' from application code results in a additional copy of Singleton services being created"

Lying answered 17/6, 2020 at 20:42 Comment(0)
L
7

The configuration system for authentication uses the Options pattern. This means that the following approach would have a similar effect to the approach shown in your question:

services.AddAuthentication()
    .AddOpenIdConnect(AuthenticationScheme, options =>
    {
        // ...
    });

services.Configure<OpenIdConnectOptions>(AuthenticationScheme, options =>
{
    options.ClientSecret = "ClientSecret";
});

This is useful because the options pattern supports DI, using something like the following:

services.AddOptions<OpenIdConnectOptions>(AuthenticationScheme)
    .Configure<ISecretRetriever>((options, secretRetriever) =>
    {
        options.ClientSecret = secretRetriever.GetClientSecret();
    });

To get access to the Configure method that works with DI, you must first call AddOptions. In this example, Configure is given a single type argument, which represents the dependency that's needed. This is passed into your configuration callback as the second parameter, after the OpenIdConnectOptions instance that's being configured.

Lillia answered 17/6, 2020 at 21:5 Comment(0)
B
0

To build off of Kirk's answer for a fuller example

// Register our custom options -- we can resolve this as IOptions<MyCustomOptions>
services.Configure<MyCustomOptions>(config.GetSection(optionsSection));

// Configure OIDC
var authBuilder = services.AddAuthentication()
    .AddOpenIdConnect(schemeName, options => ...);

// Update OIDC config with our custom options
authBuilder.Services.AddOptions<OpenIdConnectOptions>(schemeName)
    .Configure<IOptions<MyCustomOptions>>((oidcOptions, myOptions) =>
    {
        oidcOptions.ClientSecret = myOptions.Value.SecretTime;
    });

// register some other services
builder.Services.AddSingleton<Foo>(sp => {
    var myOpts = sp.GetRequiredService<IOptions<MyCustomOptions>>();
    new Foo(myOpts.Value.SecretTime)
};
Bromine answered 2/6, 2022 at 18:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.