title: Setting dynamically OpenIdConnectOptions with AddOpenIdConnect overload that requires the AuthenticationScheme as well
body: <p>I have a question related to a green ticked solution from an old question:
  <a href="https://stackoverflow.com/questions/52955238/how-can-i-set-the-authority-on-openidconnect-middleware-options-dynamically">how-can-i-set-the-authority-on-openidconnect-middleware-options-dynamically</a></p>
  
  <p>I copy it here:</p>
  
  <p><strong><em>-- START COPY --</em></strong></p>
  
  <blockquote>
    <p>While a bit tricky, it's definitely possible. Here's a simplified example, using the MSFT OIDC handler, a custom monitor and path-based tenant resolution:</p>
    
    <h3>Implement your tenant resolution logic. E.g:</h3>
  </blockquote>
  
  <pre class="lang-cs prettyprint-override"><code>public class TenantProvider
  {
      private readonly IHttpContextAccessor _httpContextAccessor;
  
      public TenantProvider(IHttpContextAccessor httpContextAccessor)
          =&gt; _httpContextAccessor = httpContextAccessor;
  
      public string GetCurrentTenant()
      {
          // This sample uses the path base as the tenant.
          // You can replace that by your own logic.
          string tenant = _httpContextAccessor.HttpContext.Request.PathBase;
          if (string.IsNullOrEmpty(tenant))
          {
              tenant = "default";
          }
  
          return tenant;
      }
  }
  </code></pre>
  
  <pre class="lang-cs prettyprint-override"><code>public void Configure(IApplicationBuilder app)
  {
      app.Use(next =&gt; context =&gt;
      {
          // This snippet uses a hardcoded resolution logic.
          // In a real world app, you'd want to customize that.
          if (context.Request.Path.StartsWithSegments("/fabrikam", out PathString path))
          {
              context.Request.PathBase = "/fabrikam";
              context.Request.Path = path;
          }
  
          return next(context);
      });
  
      app.UseAuthentication();
  
      app.UseMvc();
  }
  </code></pre>
  
  <blockquote>
    <h3>Implement a custom <code>IOptionsMonitor&lt;OpenIdConnectOptions&gt;</code>:</h3>
  </blockquote>
  
  <pre class="lang-cs prettyprint-override"><code>public class OpenIdConnectOptionsProvider : IOptionsMonitor&lt;OpenIdConnectOptions&gt;
  {
      private readonly ConcurrentDictionary&lt;(string name, string tenant), Lazy&lt;OpenIdConnectOptions&gt;&gt; _cache;
      private readonly IOptionsFactory&lt;OpenIdConnectOptions&gt; _optionsFactory;
      private readonly TenantProvider _tenantProvider;
  
      public OpenIdConnectOptionsProvider(
          IOptionsFactory&lt;OpenIdConnectOptions&gt; optionsFactory,
          TenantProvider tenantProvider)
      {
          _cache = new ConcurrentDictionary&lt;(string, string), Lazy&lt;OpenIdConnectOptions&gt;&gt;();
          _optionsFactory = optionsFactory;
          _tenantProvider = tenantProvider;
      }
  
      public OpenIdConnectOptions CurrentValue =&gt; Get(Options.DefaultName);
  
      public OpenIdConnectOptions Get(string name)
      {
          var tenant = _tenantProvider.GetCurrentTenant();
  
          Lazy&lt;OpenIdConnectOptions&gt; Create() =&gt; new Lazy&lt;OpenIdConnectOptions&gt;(() =&gt; _optionsFactory.Create(name));
          return _cache.GetOrAdd((name, tenant), _ =&gt; Create()).Value;
      }
  
      public IDisposable OnChange(Action&lt;OpenIdConnectOptions, string&gt; listener) =&gt; null;
  }
  </code></pre>
  
  <blockquote>
    <h3>Implement a custom <code>IConfigureNamedOptions&lt;OpenIdConnectOptions&gt;</code>:</h3>
  </blockquote>
  
  <pre class="lang-cs prettyprint-override"><code>public class OpenIdConnectOptionsInitializer : IConfigureNamedOptions&lt;OpenIdConnectOptions&gt;
  {
      private readonly IDataProtectionProvider _dataProtectionProvider;
      private readonly TenantProvider _tenantProvider;
  
      public OpenIdConnectOptionsInitializer(
          IDataProtectionProvider dataProtectionProvider,
          TenantProvider tenantProvider)
      {
          _dataProtectionProvider = dataProtectionProvider;
          _tenantProvider = tenantProvider;
      }
  
      public void Configure(string name, OpenIdConnectOptions options)
      {
          if (!string.Equals(name, OpenIdConnectDefaults.AuthenticationScheme, StringComparison.Ordinal))
          {
              return;
          }
  
          var tenant = _tenantProvider.GetCurrentTenant();
  
          // Create a tenant-specific data protection provider to ensure
          // encrypted states can't be read/decrypted by the other tenants.
          options.DataProtectionProvider = _dataProtectionProvider.CreateProtector(tenant);
  
          // Other tenant-specific options like options.Authority can be registered here.
      }
  
      public void Configure(OpenIdConnectOptions options)
          =&gt; Debug.Fail("This infrastructure method shouldn't be called.");
  }
  </code></pre>
  
  <blockquote>
    <h3>Register the services in your DI container:</h3>
  </blockquote>
  
  <pre class="lang-cs prettyprint-override"><code>public void ConfigureServices(IServiceCollection services)
  {
      // ...
  
      // Register the OpenID Connect handler.
      services.AddAuthentication()
          .AddOpenIdConnect();
  
      services.AddSingleton&lt;TenantProvider&gt;();
      services.AddSingleton&lt;IOptionsMonitor&lt;OpenIdConnectOptions&gt;, OpenIdConnectOptionsProvider&gt;();
      services.AddSingleton&lt;IConfigureOptions&lt;OpenIdConnectOptions&gt;, OpenIdConnectOptionsInitializer&gt;();
  }
  </code></pre>
  
  <p><strong><em>-- END COPY --</em></strong></p>
  
  <p>This works fine for me except that I would like to use another overload of the AddOpenIdConnect method, exactly the following one:</p>
  
  <pre class="lang-cs prettyprint-override"><code>public static AuthenticationBuilder AddOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, Action&lt;OpenIdConnectOptions&gt; configureOptions);
  </code></pre>
  
  <p>My solution is:
  </p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      // ...
  
      // Register the OpenID Connect handler.
      services.AddAuthentication()
          .AddOpenIdConnect("MyExternalProvider", "My External Provider", options =&gt;
             {
                 var sp = services.BuildServiceProvider();
                 var  initializer= sp.GetService&lt;IConfigureNamedOptions&lt;OpenIdConnectOptions&gt;&gt;();
                 initializer.Configure("MyExternalProvider",options); ;
             }
             );
  
      services.AddSingleton&lt;TenantProvider&gt;();
      services.AddSingleton&lt;IOptionsMonitor&lt;OpenIdConnectOptions&gt;, OpenIdConnectOptionsProvider&gt;();
      services.AddSingleton&lt;IConfigureOptions&lt;OpenIdConnectOptions&gt;, OpenIdConnectOptionsInitializer&gt;();
  }
  </code></pre>
  
  <p>My question is about if it is a good way to do it, building the Service Provider in the ConfigureServices method, to be used in a delegate?</p>