Encryption and signing credentials
+ +To protect the tokens it issues, OpenIddict uses 2 types of credentials:
+-
+
- Signing credentials are used to protect against tampering. They can be either asymmetric (e.g a RSA or ECDSA key) or symmetric. +
- Encryption credentials are used to ensure the content of tokens cannot be read by malicious parties. They can be either asymmetric (e.g a RSA key) or symmetric. +
Note
Tokens generated using the opt-in ASP.NET Core Data Protection integration rely on their own key ring, distinct from the credentials discussed in this documentation. +For more information about Data Protection, visit ASP.NET Core Data Protection.
+Registering credentials in the server options
+OpenIddict allows registering one or multiple keys (raw keys or embedded in X.509 certificates).
+Note
When multiple keys/certificates are registered (which can be useful to implement keys rotation), OpenIddict chooses the most appropriate key based on the following algorithm:
+-
+
- Symmetric keys are always chosen first, except for identity tokens, that can only be signed using asymmetric keys. +
- Asymmetric keys embedded in X.509 certificates are ordered based on the
NotAfterandNotBeforedates (certificates that are not yet valid +are not used by OpenIddict and certificates with the furthest expiration date are always preferred).
+ - X.509 certificates are always preferred to raw RSA/ECDSA keys. +
Registering an ephemeral key
+For development purposes, an ephemeral key - that is not persisted or shared across instances - can be used to sign or encrypt tokens:
+services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ options.AddEphemeralEncryptionKey()
+ .AddEphemeralSigningKey();
+ });
+Note
options.AddEphemeralEncryptionKey() generates an asymmetric RSA key which is not directly used as-is to encrypt the tokens but is used to encrypt an
+intermediate per-token symmetric key with which the token content is first encrypted using AES.
+For more information about this mechanism, read Key Encryption with RSAES OAEP.
Registering a development certificate
+For development purposes, a certificate can be generated and stored by OpenIddict in the certificates store of the user account running the OpenIddict server feature. +Unlike ephemeral keys, development certificates are persisted - but not shared across instances - and will be reused when the application host is restarted.
+services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ options.AddDevelopmentEncryptionCertificate()
+ .AddDevelopmentSigningCertificate();
+ });
+Warning
This feature is not available on .NET Framework 4.6.1: calling options.AddDevelopmentEncryptionCertificate() or options.AddDevelopmentSigningCertificate()
+will result in a PlatformNotSupportedException being thrown at runtime if no valid development certificate can be found and a new one must be generated.
Registering a key
+To register a signing or encryption key, an instance of a SecurityKey - typically a SymmetricSecurityKey or a RsaSecurityKey -
+can be provided to the options.AddSigningKey()/options.AddEncryptionKey() methods:
services.AddOpenIddict()
+ .AddServer(options =>
+ {
+ options.AddEncryptionKey(new SymmetricSecurityKey(
+ Convert.FromBase64String("DRjd/GnduI3Efzen9V9BvbNUfc/VKgXltV7Kbk9sMkY=")));
+ });
+Note
While signing keys can be either symmetric or asymmetric, OpenIddict requires registering at least one asymmetric key to sign identity tokens. +If both an asymmetric and a symmetric signing key are registered, the symmetric key will always be preferred when protecting access tokens, +authorization codes or refresh tokens, while the asymmetric key will be used to sign identity tokens, that are meant to be publicly validated.
+Registering a certificate (recommended for production-ready scenarios)
+To register a signing or encryption certificate, the options.AddSigningCertificate()/options.AddEncryptionCertificate() methods can be called
+with an instance of X509Certificate2. Alternatively, a unique thumbprint identifying the certificate in the machine or user certificate store
+of the operating system can also be provided.
In production, it is recommended to use two RSA certificates, distinct from the certificate(s) used for HTTPS: one for encryption, one for signing.
+Certificates can be generated and self-signed locally using the .NET Core CertificateRequest API:
using var algorithm = RSA.Create(keySizeInBits: 2048);
+
+var subject = new X500DistinguishedName("CN=Fabrikam Encryption Certificate");
+var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment, critical: true));
+
+var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(2));
+var data = certificate.Export(X509ContentType.Pfx, string.Empty);
+using var algorithm = RSA.Create(keySizeInBits: 2048);
+
+var subject = new X500DistinguishedName("CN=Fabrikam Signing Certificate");
+var request = new CertificateRequest(subject, algorithm, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, critical: true));
+
+var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(2));
+var data = certificate.Export(X509ContentType.Pfx, string.Empty);
+The best place to store your certificates will mostly depend on your host:
+-
+
- For IIS applications, storing the certificates in the machine store is the recommended option. +
- On Azure, certificates can be uploaded and exposed to Azure App Services applications using the special
WEBSITE_LOAD_CERTIFICATESflag. +For more information, visit https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code
+
Importing credentials in the validation options
+Using the options.UseLocalServer() integration
+When the API and the authorization server are part of the same project, both the signing and
+encryption credentials can be easily imported by calling options.UseLocalServer():
services.AddOpenIddict()
+ .AddValidation(options =>
+ {
+ options.UseLocalServer();
+ });
+Using OpenID Connect discovery (asymmetric signing keys only)
+When the API and the authorization server are hosted in different applications, +standard OpenID Connect discovery can be used to automatically import asymmetric signing keys:
+services.AddOpenIddict()
+ .AddValidation(options =>
+ {
+ options.SetIssuer("https://localhost:44319/");
+ options.UseSystemNetHttp();
+ });
+Registering a symmetric signing key in the token validation parameters
+Unlike asymmetric signing keys, symmetric keys - used with HMAC-based algorithms like HS256 - cannot +be safely exposed by an OpenID Connect discovery endpoint. As such, they can't be automatically imported by the OpenIddict validation handler. +For applications that require using a symmetric signing key, the advanced configuration APIs can be used to register it in the token validation options:
+services.AddOpenIddict()
+ .AddValidation(options =>
+ {
+ options.Configure(options => options.TokenValidationParameters.IssuerSigningKey =
+ new SymmetricSecurityKey(
+ Convert.FromBase64String("DRjd/GnduI3Efzen9V9BvbNUfc/VKgXltV7Kbk9sMkY=")));
+ });
+Registering an encryption key or certificate
+To import an encryption key/certificate, the same overloads as the ones exposed by the OpenIddict server feature can be used:
+services.AddOpenIddict()
+ .AddValidation(options =>
+ {
+ options.AddEncryptionCertificate("b82f36609cdaff9a95de60e8d5ac774b2e496c4b");
+ });
+