diff --git a/Abblix.Jwt/JsonWebKey.cs b/Abblix.Jwt/JsonWebKey.cs
index 15ae2ebd..1b63afc6 100644
--- a/Abblix.Jwt/JsonWebKey.cs
+++ b/Abblix.Jwt/JsonWebKey.cs
@@ -34,41 +34,48 @@ namespace Abblix.Jwt;
//TODO consider to split this class into specialized subclasses (RSA/EllipticCurve)
///
-/// Represents a JSON Web Key (JWK), a data structure that represents a cryptographic key in JSON format.
-/// The class supports various key types including RSA and Elliptic Curve, and is capable of representing both public and private keys.
+/// Represents a JSON Web Key (JWK), a versatile structure for representing cryptographic keys using JSON.
+/// It supports various cryptographic algorithms, including RSA and Elliptic Curve, and can represent both
+/// public and private keys. JWKs are crucial for digital signatures, encryption, and ensuring secure
+/// communication in web-based protocols.
///
-public class JsonWebKey
+public record JsonWebKey
{
///
- /// Key type (kty). Identifies the cryptographic algorithm family used with the key, such as "RSA" or "EC" for Elliptic Curve.
+ /// Identifies the cryptographic algorithm family used with the key, such as RSA or EC (Elliptic Curve),
+ /// specifying the key's type and its intended cryptographic use.
///
[JsonPropertyName("kty")]
[JsonPropertyOrder(1)]
public string? KeyType { get; set; }
///
- /// Intended use of the key (use). Indicates how the key is meant to be used, such as "sig" for signing or "enc" for encryption.
+ /// Indicates the intended use of the key, for example, "sig" (signature) for signing operations or
+ /// "enc" (encryption) for encryption operations, guiding clients on how to use the key appropriately.
///
[JsonPropertyName("use")]
[JsonPropertyOrder(2)]
public string? Usage { get; set; }
///
- /// Algorithm (alg). Specifies the algorithm that the key is intended to be used with.
+ /// Specifies the algorithm intended for use with the key, aligning with JWT and JWA specifications
+ /// to ensure interoperability and secure key management.
///
[JsonPropertyName("alg")]
[JsonPropertyOrder(3)]
public string? Algorithm { get; set; }
///
- /// Key ID (kid). A hint indicating which specific key owned by the signer should be used.
+ /// A unique identifier for the key, facilitating key selection and management in multi-key environments,
+ /// enabling clients and servers to reference and utilize the correct key for cryptographic operations.
///
[JsonPropertyName("kid")]
[JsonPropertyOrder(4)]
public string? KeyId { get; set; }
///
- /// X.509 Certificate Chain (x5c). Contains a chain of one or more PKIX certificates.
+ /// Contains a chain of one or more PKIX certificates (RFC 5280), offering a method to associate X.509
+ /// certificates with the key for validation and trust chain establishment in secure communications.
///
[JsonPropertyName("x5c")]
[JsonPropertyOrder(5)]
@@ -76,7 +83,8 @@ public class JsonWebKey
public byte[][]? Certificates { get; set; }
///
- /// X.509 Certificate SHA-1 Thumbprint (x5t). A base64url-encoded SHA-1 thumbprint (a.k.a. digest) of the DER encoding of an X.509 certificate.
+ /// A base64url-encoded SHA-1 thumbprint of the DER encoding of an X.509 certificate, providing a compact
+ /// means to associate a certificate with the JWK for verification purposes without transmitting the full certificate.
///
[JsonPropertyName("x5t")]
[JsonPropertyOrder(5)]
@@ -169,4 +177,30 @@ public class JsonWebKey
[JsonPropertyOrder(16)]
[JsonConverter(typeof(Base64UrlTextEncoderConverter))]
public byte[]? FirstCrtCoefficient { get; set; }
+
+ ///
+ /// Prepares a sanitized version of the JWK that excludes private key information unless explicitly included,
+ /// suitable for public sharing while preserving the integrity of sensitive data.
+ ///
+ /// Whether to include private key data in the sanitized output.
+ ///
+ /// A new instance of with or without private key data based on the input parameter.
+ ///
+ public JsonWebKey Sanitize(bool includePrivateKeys)
+ {
+ return includePrivateKeys switch
+ {
+ true when PrivateKey is { Length: > 0} => this,
+ true => throw new InvalidOperationException($"There is no private key for kid={KeyId}"),
+ false => this with
+ {
+ PrivateKey = null,
+ FirstCrtCoefficient = null,
+ FirstPrimeFactor = null,
+ FirstFactorCrtExponent = null,
+ SecondPrimeFactor = null,
+ SecondFactorCrtExponent = null,
+ }
+ };
+ }
}
diff --git a/Abblix.Oidc.Server/Common/Configuration/OidcOptions.cs b/Abblix.Oidc.Server/Common/Configuration/OidcOptions.cs
index 316a63d8..8130dfba 100644
--- a/Abblix.Oidc.Server/Common/Configuration/OidcOptions.cs
+++ b/Abblix.Oidc.Server/Common/Configuration/OidcOptions.cs
@@ -27,9 +27,7 @@
// For more information, please refer to the license agreement located at:
// https://github.com/Abblix/Oidc.Server/blob/master/README.md
-using System.Security.Cryptography.X509Certificates;
using Abblix.Jwt;
-using Abblix.Oidc.Server.Common.Constants;
using Abblix.Oidc.Server.Features.ClientInformation;
using Abblix.Oidc.Server.Model;
@@ -41,215 +39,122 @@ namespace Abblix.Oidc.Server.Common.Configuration;
public record OidcOptions
{
///
- /// The OIDC discovery options.
+ /// Configuration options for OIDC discovery. These options control how the OIDC server advertises its capabilities
+ /// and endpoints to clients through the OIDC Discovery mechanism. Proper configuration ensures that clients can
+ /// dynamically discover information about the OIDC server, such as URLs for authorization, token, userinfo, and
+ /// JWKS endpoints, supported scopes, response types, and more.
///
public DiscoveryOptions Discovery { get; set; } = new();
///
- /// The issuer identifier to be used in tokens. It is useful for scenarios where the issuer
- /// needs to be consistent and predefined, such as environments with multiple hosts.
+ /// Represents the unique identifier of the OIDC server.
+ /// It is recommended to use a URL that is controlled by the entity operating the OIDC server, and it should be
+ /// consistent across different environments to maintain trust with client applications.
///
public string? Issuer { get; set; }
///
- /// The client configurations supported by the OIDC server.
+ /// A collection of client configurations supported by this OIDC server. Each object
+ /// defines the settings and capabilities of a registered client, including client ID, client secrets,
+ /// redirect URIs, and other OAuth2/OIDC parameters. Proper client configuration is essential for securing client
+ /// applications and enabling them to interact with the OIDC server according to the OAuth2 and OIDC specifications.
///
public IEnumerable Clients { get; set; } = Array.Empty();
///
- /// The URI for account selection during authentication.
+ /// The URL to a user interface or service that allows users to select an account during the authentication process.
+ /// This is useful in scenarios where users have multiple accounts and need to choose which one to use for signing in.
///
public Uri? AccountSelectionUri { get; set; }
///
- /// The URI for obtaining user consent during authentication.
+ /// The URL to a user interface or service for obtaining user consent during the authentication process. Consent is
+ /// often required when the client application requests access to user data or when sharing information between
+ /// different parties. This URI should point to a page or API that can manage consent workflows and communicate
+ /// the user's decisions back to the OIDC server.
///
public Uri? ConsentUri { get; set; }
///
- /// The URI for handling interactions during the authentication process.
+ /// The URL to a user interface or service for handling additional interactions required during the authentication
+ /// process. This can include multi-factor authentication, user consent, or any custom interaction required by the
+ /// authentication flow. The OIDC server can redirect users to this URI when additional interaction is needed.
///
public Uri? InteractionUri { get; set; }
///
- /// The URI for initiating a login process.
+ /// The URL to initiate the login process. This URI is typically used in scenarios where the OIDC server needs to
+ /// direct users to a specific login interface or when integrating with external identity providers. Configuring
+ /// this URI allows the OIDC server to delegate the initial user authentication step to another service or UI.
///
public Uri? LoginUri { get; set; }
///
- /// The parameter name for authorization request identifier.
+ /// The name of the parameter used by the OIDC server to pass the authorization request identifier. This parameter
+ /// name is used in URLs and requests to reference specific authorization requests, especially in advanced features
+ /// like Pushed Authorization Requests (PAR). Customizing this parameter name can help align with specific client
+ /// requirements or naming conventions.
///
public string RequestUriParameterName { get; set; } = AuthorizationRequest.Parameters.RequestUri;
///
- /// Specifies which OIDC endpoints are enabled.
+ /// Specifies which OIDC endpoints are enabled on the server. This property allows for fine-grained control over
+ /// the available functionality, enabling or disabling specific endpoints based on the server's role, security
+ /// considerations, or operational requirements. By default, all endpoints are enabled.
///
public OidcEndpoints EnabledEndpoints { get; set; } = OidcEndpoints.All;
///
- /// The certificates used for signing tokens.
+ /// The collection of JSON Web Keys (JWK) used for signing tokens issued by the OIDC server.
+ /// Signing tokens is a critical security measure that ensures the integrity and authenticity of the tokens.
+ /// These keys are used to digitally sign ID tokens, access tokens, and other JWTs issued by the server,
+ /// allowing clients to verify that the tokens have not been tampered with and were indeed issued by this server.
+ /// It is recommended to rotate these keys periodically to maintain the security of the token signing process.
///
- public IReadOnlyCollection SigningCertificates { get; set; } = Array.AsReadOnly(Array.Empty());
+ public IReadOnlyCollection SigningKeys { get; set; } = Array.Empty();
///
- /// The options related to the check session cookie.
+ /// Options related to the check session mechanism in OIDC. This configuration controls how the OIDC server manages
+ /// session state information, allowing clients to monitor the login session's status. Properly configuring these
+ /// options ensures that clients can react to session changes (e.g., logout) in a timely and secure manner.
///
public CheckSessionCookieOptions CheckSessionCookie { get; set; } = new();
///
- /// The duration of a login session's expiration.
+ /// The duration after which a login session expires. This setting determines how long a user's authentication
+ /// session remains valid before requiring re-authentication. Configuring this duration is essential for balancing
+ /// security concerns with usability, particularly in environments with varying security requirements.
///
public TimeSpan LoginSessionExpiresIn { get; set; } = TimeSpan.FromMinutes(10);
///
- /// Indicates support for claims parameters in requests.
- ///
- public bool ClaimsParameterSupported { get; set; } = true;
-
- ///
- /// A list of scopes supported by the service.
- ///
- public IList ScopesSupported { get; set; } = new List
- {
- Scopes.OpenId,
- Scopes.Profile,
- Scopes.Email,
- Scopes.Phone,
- Scopes.Address,
- Scopes.OfflineAccess,
- };
-
- ///
- /// The claims supported by the service.
- ///
- public IList ClaimsSupported { get; set; } = new List
- {
- JwtClaimTypes.Subject,
- JwtClaimTypes.Email,
- JwtClaimTypes.EmailVerified,
- JwtClaimTypes.PhoneNumber,
- JwtClaimTypes.PhoneNumberVerified,
- };
-
- ///
- /// The response types supported by the service.
- ///
- public IList ResponseTypesSupported { get; set; } = new List
- {
- ResponseTypes.Code,
- ResponseTypes.Token,
- ResponseTypes.IdToken,
- string.Join(" ", ResponseTypes.IdToken, ResponseTypes.Token),
- string.Join(" ", ResponseTypes.Code, ResponseTypes.IdToken),
- string.Join(" ", ResponseTypes.Code, ResponseTypes.Token),
- string.Join(" ", ResponseTypes.Code, ResponseTypes.IdToken, ResponseTypes.Token),
- };
-
- ///
- /// The response modes supported by the service.
- ///
- public IList ResponseModesSupported { get; set; } = new List
- {
- ResponseModes.FormPost,
- ResponseModes.Query,
- ResponseModes.Fragment,
- };
-
- ///
- /// A list of algorithms supported for signing ID tokens.
- ///
- public IList IdTokenSigningAlgorithmValuesSupported { get; set; } = new List
- {
- SigningAlgorithms.None,
- SigningAlgorithms.RS256,
- };
-
- ///
- /// A list of subject types supported by the OIDC service.
- ///
- public IList SubjectTypesSupported { get; set; } = new List
- {
- SubjectTypes.Public,
- SubjectTypes.Pairwise,
- };
-
- ///
- /// A list of supported methods for code challenge in PKCE (Proof Key for Code Exchange).
- ///
- public IList CodeChallengeMethodsSupported { get; set; } = new List
- {
- CodeChallengeMethods.Plain,
- CodeChallengeMethods.S256,
- };
-
- ///
- /// Indicates whether the request parameter is supported by the OIDC service.
- ///
- public bool RequestParameterSupported { get; set; } = true;
-
- ///
- /// A list of prompt values supported by the OIDC service.
- ///
- public IList PromptValuesSupported { get; set; } = new List
- {
- Prompts.None,
- Prompts.Login,
- Prompts.Consent,
- Prompts.SelectAccount,
- Prompts.Create,
- };
-
- ///
- /// Options for configuring a new client in the OIDC service.
+ /// Configuration options for registering new clients dynamically in the OIDC server. These options define default
+ /// values and constraints for new client registrations, facilitating dynamic and secure client onboarding processes.
///
public NewClientOptions NewClientOptions { get; init; } = new();
///
- /// A list of algorithms supported for signing UserInfo responses.
- ///
- public IList UserInfoSigningAlgValuesSupported { get; set; } = new List
- {
- SigningAlgorithms.None,
- SigningAlgorithms.RS256,
- };
-
- ///
- /// A list of algorithms supported for signing request objects.
- ///
- public IList RequestObjectSigningAlgValuesSupported { get; set; } = new List
- {
- SigningAlgorithms.None,
- SigningAlgorithms.RS256,
- };
-
- ///
- /// The encryption certificates for the OpenID Connect service tokens.
+ /// The collection of JSON Web Keys (JWK) used for encrypting tokens or sensitive information sent to the clients.
+ /// Encryption is essential for protecting sensitive data within tokens, especially when tokens are passed through
+ /// less secure channels or when storing tokens at the client side. These keys are utilized to encrypt ID tokens and,
+ /// optionally, access tokens when the OIDC server sends them to clients. Clients use the corresponding public keys
+ /// to decrypt the tokens and access the contained claims.
///
- public IList EncryptionCertificates { get; set; } = new List();
+ public IReadOnlyCollection EncryptionKeys { get; set; } = Array.Empty();
///
- /// The duration for which a pushed authorization request (PAR) is considered valid.
+ /// The duration for which a Pushed Authorization Request (PAR) is valid. PAR is a security enhancement that allows
+ /// clients to pre-register authorization requests directly with the authorization server. This duration specifies
+ /// the maximum time a pre-registered request is considered valid, balancing the need for security with usability
+ /// in completing the authorization process.
///
- ///
- /// This property defines the lifespan of a pushed authorization request. Pushed authorization requests are
- /// a security feature in OIDC that allows clients to send authorization requests directly to the authorization
- /// server via a backchannel connection, rather than through the user's browser. This duration specifies
- /// how long the server should consider the request valid after it has been received. It is important to balance
- /// security and usability when configuring this value, ensuring that requests are valid long enough for users
- /// to complete the authentication process without leaving too large a window for potential misuse.
- ///
public TimeSpan PushedAuthorizationRequestExpiresIn { get; set; } = TimeSpan.FromMinutes(1);
///
- /// The JWT used for licensing and configuration validation of the OIDC service.
+ /// A JWT used for licensing and configuration validation of the OIDC service. This token contains claims that the
+ /// OIDC service uses to validate its configuration, features, and licensing status, ensuring the service operates
+ /// within its licensed capabilities. Proper validation of this token is crucial for the service's legal and functional
+ /// compliance.
///
- ///
- /// This property holds a JSON Web Token (JWT) that the OIDC service uses to validate its configuration and
- /// licensing status. The token typically contains claims that the service decodes to determine the features
- /// and capabilities that are enabled, based on the licensing agreement. Proper validation of this token
- /// is crucial for ensuring that the service operates within the terms of its licensing and has access
- /// to the correct set of features. The format and content of this token are determined by the service provider
- /// and may include information such as the license expiry date, the licensed feature set and other relevant data.
- ///
public string? LicenseJwt { get; set; }
}
diff --git a/Abblix.Oidc.Server/Common/Implementation/ServiceKeysProvider.cs b/Abblix.Oidc.Server/Common/Implementation/OidcOptionsKeysProvider.cs
similarity index 86%
rename from Abblix.Oidc.Server/Common/Implementation/ServiceKeysProvider.cs
rename to Abblix.Oidc.Server/Common/Implementation/OidcOptionsKeysProvider.cs
index ddaab61d..cea07923 100644
--- a/Abblix.Oidc.Server/Common/Implementation/ServiceKeysProvider.cs
+++ b/Abblix.Oidc.Server/Common/Implementation/OidcOptionsKeysProvider.cs
@@ -37,17 +37,16 @@
namespace Abblix.Oidc.Server.Common.Implementation;
///
-/// Provides access to JSON Web Keys (JWK) used for encryption and signing JWT tokens,
-/// based on the preconfigured X509 certificates defined in OIDC options.
+/// Provides access to JSON Web Keys (JWK) used for encryption and signing JWT tokens.
///
///
/// This implementation provides keys for encryption and signing purposes by mapping X509 certificates to JWK format.
/// It is recommended to implement a dynamic resolution mechanism in production environments
/// to enable seamless certificate replacement without the need for service reloading.
///
-internal class ServiceKeysProvider : IAuthServiceKeysProvider
+internal class OidcOptionsKeysProvider : IAuthServiceKeysProvider
{
- public ServiceKeysProvider(IOptions options)
+ public OidcOptionsKeysProvider(IOptions options)
{
_options = options;
}
@@ -62,9 +61,8 @@ public ServiceKeysProvider(IOptions options)
public IAsyncEnumerable GetEncryptionKeys(bool includePrivateKeys)
{
var jsonWebKeys =
- from cert in _options.Value.EncryptionCertificates
- orderby cert.NotAfter descending
- select cert.ToJsonWebKey(includePrivateKeys);
+ from jwk in _options.Value.EncryptionKeys
+ select jwk.Sanitize(includePrivateKeys);
return jsonWebKeys.AsAsync();
}
@@ -77,9 +75,8 @@ orderby cert.NotAfter descending
public IAsyncEnumerable GetSigningKeys(bool includePrivateKeys)
{
var jsonWebKeys =
- from cert in _options.Value.SigningCertificates
- orderby cert.NotAfter descending
- select cert.ToJsonWebKey(includePrivateKeys);
+ from jwk in _options.Value.SigningKeys
+ select jwk.Sanitize(includePrivateKeys);
return jsonWebKeys.AsAsync();
}
diff --git a/Abblix.Oidc.Server/Features/ServiceCollectionExtensions.cs b/Abblix.Oidc.Server/Features/ServiceCollectionExtensions.cs
index 4573ec9e..f43ac8f2 100644
--- a/Abblix.Oidc.Server/Features/ServiceCollectionExtensions.cs
+++ b/Abblix.Oidc.Server/Features/ServiceCollectionExtensions.cs
@@ -270,7 +270,7 @@ public static IServiceCollection AddIdentityToken(this IServiceCollection servic
public static IServiceCollection AddAuthServiceJwt(this IServiceCollection services)
{
return services
- .AddSingleton()
+ .AddSingleton()
.AddSingleton()
.AddSingleton();
diff --git a/Abblix.Oidc.Server/Features/Tokens/Formatters/AuthServiceJwtFormatter.cs b/Abblix.Oidc.Server/Features/Tokens/Formatters/AuthServiceJwtFormatter.cs
index af2e35b0..606e076c 100644
--- a/Abblix.Oidc.Server/Features/Tokens/Formatters/AuthServiceJwtFormatter.cs
+++ b/Abblix.Oidc.Server/Features/Tokens/Formatters/AuthServiceJwtFormatter.cs
@@ -64,7 +64,7 @@ public AuthServiceJwtFormatter(
///
public async Task FormatAsync(JsonWebToken token)
{
- // Select the appropriate signing key based on the JWT's specified algorithm
+ // Select the appropriate signing key based on the JWT specified algorithm
var signingCredentials = await _serviceKeysProvider.GetSigningKeys(true)
.FirstByAlgorithmAsync(token.Header.Algorithm);