Skip to content

IConfigurationResolver

The IConfigurationResolver interface provides an alternative mechanism for supplying OpenID configuration. Rather than configuring OpenID at application startup, the resolver returns OpenID configuration on demand as it is requested. This approach is intended for highly dynamic, multi-tenant, or frequently changing configurations.

The following code adds the OpenID services and specifies a OpenID configuration resolver.

// Add OpenID services.
builder.Services.AddOpenIDProvider()
    .AddOpenIDConfigurationResolver<CustomConfigurationResolver>();

The ConfigurationName property identifies the OpenID configuration being requested and may be used to support multiple logical configurations or tenants.

Example Resolver

The following is an example of implementing IConfigurationResolver.

In practice, these values are typically retrieved from a database or other external configuration store rather than being hard-coded.

using ComponentSpace.OpenID.Configuration.Resolver;

public class ConfigurationResolver : IConfigurationResolver
{
    public string? ConfigurationName { get; set; }

    public Task<ProviderConfiguration> GetProviderConfigurationAsync()
    {
        return Task.FromResult(new ProviderConfiguration()
        {
            ProviderMetadata = new ProviderMetadata()
            {
                Issuer = "https://ExampleOpenIDProvider",
                AuthorizationEndpoint = "/openid/authorize",
                TokenEndpoint = "/openid/token",
                UserinfoEndpoint = "/openid/userinfo",
                JwksUri = "/openid/keys",
                EndSessionEndpoint = "/openid/logout",
                ScopesSupported = new string[] { "openid" },
                ResponseTypesSupported = new string[] { "code", "id_token", "id_token token", "code id_token", "code token", "code id_token token" },
                ResponseModesSupported = new string[] { "query", "fragment", "form_post" },
                GrantTypesSupported = new string[] { "authorization_code", "implicit", "refresh_token", "client_credentials" },
                SubjectTypesSupported = new string[] { "public" },
                IdTokenSigningAlgValuesSupported = new string[] { "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" },
                IdTokenEncryptionAlgValuesSupported = new string[] { "A128KW", "A192KW", "A256KW", "dir", "RSA1_5", "RSA-OAEP" },
                IdTokenEncryptionEncValuesSupported = new string[] { "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" },
                UserinfoSigningAlgValuesSupported = new string[] { "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" },
                UserinfoEncryptionAlgValuesSupported = new string[] { "A128KW", "A192KW", "A256KW", "dir", "RSA1_5", "RSA-OAEP" },
                UserinfoEncryptionEncValuesSupported = new string[] { "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" },
                RequestObjectSigningAlgValuesSupported = new string[] { "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" },
                RequestObjectEncryptionAlgValuesSupported = new string[] { "A128KW", "A192KW", "A256KW", "dir", "RSA1_5", "RSA-OAEP" },
                RequestObjectEncryptionEncValuesSupported = new string[] { "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" },
                TokenEndpointAuthMethodsSupported = new string[] { "client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none" },
                TokenEndpointAuthSigningAlgValuesSupported = new string[] { "HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512" },
                DisplayValuesSupported = new string[] { "page", "popup", "touch", "wap" },
                ClaimsSupported = new string[] { "amr", "aud", "email", "exp", "family_name", "given_name", "iat", "idp", "iss", "jti", "middle_name", "name", "nbf", "nonce", "preferred_username", "sub", "ver" },
                CodeChallengeMethodsSupported = new string[] { "plain", "S256" },
                RequestParameterSupported = true,
                RequestUriParameterSupported = true
            },
            ProviderCertificates = new Certificate[]
            {
                new Certificate()
                {
                    FileName = "certificates/op.pfx",
                    Password = "password"
                }
            }
        });
    }

    public Task<ClientConfiguration> GetClientConfigurationAsync(string? clientID)
    {
        switch (clientID)
        {
            case "wLpJpHADUqEmmAltrZX87yUMz8lgweWs":
                return Task.FromResult(new ClientConfiguration()
                {
                    Description = "Example OpenID Client",
                    ClientID = "wLpJpHADUqEmmAltrZX87yUMz8lgweWs",
                    ClientSecret = "P41HXh7SptRM6rV4xjgdVmUkXssibunr",
                    RedirectUris = new string[] { "https://localhost:44389/signin-oidc" },
                    PostLogoutRedirectUris = new string[] { "https://localhost:44389/signout-callback-oidc" },
                    ClientCertificates = new Certificate[]
                    {
                        new Certificate()
                        {
                            FileName = "certificates/client.cer",
                        }
                    }
                });

            default:
                throw new InvalidClientException();
        }
    }
}