/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System.Security.Claims;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Tokens;
namespace OpenIddict.Validation;
///
/// Provides various settings needed to configure the OpenIddict validation handler.
///
public sealed class OpenIddictValidationOptions
{
///
/// Gets the list of encryption credentials used by the OpenIddict validation services.
/// Note: the encryption credentials are not used to protect/unprotect tokens issued
/// by ASP.NET Core Data Protection, that uses its own key ring, configured separately.
///
///
/// Note: OpenIddict automatically sorts the credentials based on the following algorithm:
///
/// - Symmetric keys are always preferred when they can be used for the operation (e.g token encryption).
/// - X.509 keys are always preferred to non-X.509 asymmetric keys.
/// - X.509 keys with the furthest expiration date are preferred.
/// - X.509 keys whose backing certificate is not yet valid are never preferred.
///
///
public List EncryptionCredentials { get; } = [];
///
/// Gets the list of signing credentials used by the OpenIddict validation services.
/// Multiple credentials can be added to support key rollover, but if X.509 keys
/// are used, at least one of them must have a valid creation/expiration date.
/// Note: the signing credentials are not used to protect/unprotect tokens issued
/// by ASP.NET Core Data Protection, that uses its own key ring, configured separately.
///
///
/// Note: OpenIddict automatically sorts the credentials based on the following algorithm:
///
/// - Symmetric keys are always preferred when they can be used for the operation (e.g token signing).
/// - X.509 keys are always preferred to non-X.509 asymmetric keys.
/// - X.509 keys with the furthest expiration date are preferred.
/// - X.509 keys whose backing certificate is not yet valid are never preferred.
///
///
public List SigningCredentials { get; } = [];
///
/// Gets or sets the period of time client assertions remain valid after being issued. The default value is 5 minutes.
/// While not recommended, this property can be set to to issue client assertions that never expire.
///
public TimeSpan? ClientAssertionLifetime { get; set; } = TimeSpan.FromMinutes(5);
///
/// Gets or sets the JWT handler used to protect and unprotect tokens.
///
public JsonWebTokenHandler JsonWebTokenHandler { get; set; } = new()
{
SetDefaultTimesOnTokenCreation = false
};
///
/// Gets the list of the handlers responsible for processing the OpenIddict validation operations.
/// Note: the list is automatically sorted based on the order assigned to each handler descriptor.
/// As such, it MUST NOT be mutated after options initialization to preserve the exact order.
///
public List Handlers { get; } = [.. OpenIddictValidationHandlers.DefaultHandlers];
///
/// Gets or sets the type of validation used by the OpenIddict validation services.
/// By default, local validation is always used.
///
public OpenIddictValidationType ValidationType { get; set; } = OpenIddictValidationType.Direct;
///
/// Gets or sets the client identifier sent to the authorization server when using remote validation.
///
public string? ClientId { get; set; }
///
/// Gets or sets the client secret sent to the authorization server when using remote validation.
///
///
/// Note: client authentication based on shared secrets is not recommended and should
/// only be used for backward compatibility with legacy applications that only support
/// client secrets. When possible, consider using public/private key pairs or TLS client
/// certificates instead, as these client authentication methods are significantly safer.
///
public string? ClientSecret { get; set; }
///
/// Gets or sets a boolean indicating whether a database call is made
/// to validate the authorization entry associated with the received tokens.
/// Note: enabling this option may have an impact on performance and
/// can only be used with an OpenIddict-based authorization server.
///
public bool EnableAuthorizationEntryValidation { get; set; }
///
/// Gets or sets a boolean indicating whether a database call is made
/// to validate the session entry associated with the received tokens.
/// Note: enabling this option may have an impact on performance and
/// can only be used with an OpenIddict-based authorization server.
///
public bool EnableSessionEntryValidation { get; set; }
///
/// Gets or sets a boolean indicating whether a database call is made
/// to validate the token entry associated with the received tokens.
/// Note: enabling this option may have an impact on performance but
/// is required when the OpenIddict server emits reference tokens.
///
public bool EnableTokenEntryValidation { get; set; }
///
/// Gets or sets the issuer that will be attached to the
/// instances created by the OpenIddict validation stack.
///
///
/// Note: if this property is not explicitly set, the
/// issuer URI is automatically used as a fallback value.
///
public string? ClaimsIssuer { get; set; }
///
/// Gets or sets the absolute URI of the OAuth 2.0/OpenID Connect server.
///
public Uri? Issuer { get; set; }
///
/// Gets or sets the URI of the configuration endpoint exposed by the server.
/// When the URI is relative, must be set and absolute.
///
public Uri? ConfigurationEndpoint { get; set; }
///
/// Gets or sets the OAuth 2.0/OpenID Connect static server configuration, if applicable.
///
public OpenIddictConfiguration? Configuration { get; set; }
///
/// Gets or sets the configuration manager used to retrieve
/// and cache the OAuth 2.0/OpenID Connect server configuration.
///
public IConfigurationManager ConfigurationManager { get; set; } = default!;
///
/// Gets the intended audiences of this resource server.
/// Setting this property is recommended when the authorization
/// server issues access tokens for multiple distinct resource servers.
///
public HashSet Audiences { get; } = new(StringComparer.Ordinal);
///
/// Gets the OAuth 2.0 client authentication methods enabled for this application.
///
public HashSet ClientAuthenticationMethods { get; } = new(StringComparer.Ordinal)
{
// Note: client_secret_basic is deliberately not added here as it requires
// a dedicated event handler (typically provided by the HTTP integration)
// to attach the client credentials to the standard Authorization header.
//
// The System.Net.Http integration supports the client_secret_basic,
// self_signed_tls_client_auth and tls_client_auth authentication
// methods and automatically add them to this list at runtime.
OpenIddictConstants.ClientAuthenticationMethods.ClientSecretPost,
OpenIddictConstants.ClientAuthenticationMethods.PrivateKeyJwt
};
///
/// Gets the token validation parameters used by the OpenIddict validation services.
///
public TokenValidationParameters TokenValidationParameters { get; } = new()
{
AuthenticationType = TokenValidationParameters.DefaultAuthenticationType,
ClockSkew = TimeSpan.Zero,
NameClaimType = Claims.Name,
RoleClaimType = Claims.Role,
// In previous versions of OpenIddict (1.x and 2.x), all the JWT tokens (access and identity tokens)
// were issued with the generic "typ": "JWT" header. To prevent confused deputy and token substitution
// attacks, a special "token_usage" claim was added to the JWT payload to convey the actual token type.
// This validator overrides the default logic used by IdentityModel to resolve the type from this claim.
TypeValidator = static (type, token, parameters) =>
{
// If available, try to resolve the actual type from the "token_usage" claim.
if (((JsonWebToken) token).TryGetPayloadValue(Claims.TokenUsage, out string usage))
{
type = usage switch
{
"access_token" => JsonWebTokenTypes.AccessToken,
"id_token" => JsonWebTokenTypes.GenericJsonWebToken,
_ => throw new NotSupportedException(SR.GetResourceString(SR.ID0269))
};
}
// Assume that tokens that don't have an explicit "typ" header attached are generic JSON Web Tokens.
if (string.IsNullOrEmpty(type))
{
type = JsonWebTokenTypes.GenericJsonWebToken;
}
// Note: unlike IdentityModel, this custom validator deliberately uses case-insensitive comparisons.
if (parameters.ValidTypes is not null && parameters.ValidTypes.Any() &&
!parameters.ValidTypes.Contains(type, StringComparer.OrdinalIgnoreCase))
{
throw new SecurityTokenInvalidTypeException(SR.GetResourceString(SR.ID0271))
{
InvalidType = type
};
}
return type;
},
// Note: audience and lifetime are manually validated by OpenIddict itself.
ValidateAudience = false,
ValidateLifetime = false
};
///
/// Gets or sets the time provider.
///
///
/// Note: if this property is not explicitly set, the time provider is
/// automatically resolved from the dependency injection container.
/// If no service can be found, is used.
///
public TimeProvider TimeProvider { get; set; } = default!;
}