diff --git a/samples/Mvc.Server/Startup.cs b/samples/Mvc.Server/Startup.cs
index aae19c60..f979a8d7 100644
--- a/samples/Mvc.Server/Startup.cs
+++ b/samples/Mvc.Server/Startup.cs
@@ -44,11 +44,13 @@ namespace Mvc.Server {
.AllowRefreshTokenFlow()
// During development, you can disable the HTTPS requirement.
- .DisableHttpsRequirement();
+ .DisableHttpsRequirement()
+
+ // Register a new ephemeral key, that is discarded when the application
+ // shuts down. Tokens signed using this key are automatically invalidated.
+ // This method should only be used during development.
+ .AddEphemeralSigningKey();
- // Note: if you don't explicitly register a signing key, one is automatically generated and
- // persisted on the disk. If the key cannot be persisted, an exception is thrown.
- //
// On production, using a X.509 certificate stored in the machine store is recommended.
// You can generate a self-signed certificate using Pluralsight's self-cert utility:
// https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
diff --git a/src/OpenIddict.Core/OpenIddictBuilder.cs b/src/OpenIddict.Core/OpenIddictBuilder.cs
index fe962912..f21bd78f 100644
--- a/src/OpenIddict.Core/OpenIddictBuilder.cs
+++ b/src/OpenIddict.Core/OpenIddictBuilder.cs
@@ -10,11 +10,13 @@ using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using AspNet.Security.OpenIdConnect.Extensions;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
using OpenIddict;
namespace Microsoft.AspNetCore.Builder {
@@ -276,6 +278,59 @@ namespace Microsoft.AspNetCore.Builder {
});
}
+ ///
+ /// Registers a new ephemeral key used to sign the tokens issued by OpenIddict: the key
+ /// is discarded when the application shuts down and tokens signed using this key are
+ /// automatically invalidated. This method should only be used during development:
+ /// on production, using a X.509 certificate stored in the machine store is recommended.
+ ///
+ /// The .
+ public virtual OpenIddictBuilder AddEphemeralSigningKey() {
+ // Note: a 1024-bit key might be returned by RSA.Create() on .NET Desktop/Mono,
+ // where RSACryptoServiceProvider is still the default implementation and
+ // where custom implementations can be registered via CryptoConfig.
+ // To ensure the key size is always acceptable, replace it if necessary.
+ var algorithm = RSA.Create();
+
+ if (algorithm.KeySize < 2048) {
+ algorithm.KeySize = 2048;
+ }
+
+#if NET451
+ // Note: RSACng cannot be used as it's not available on Mono.
+ if (algorithm.KeySize < 2048 && algorithm is RSACryptoServiceProvider) {
+ algorithm.Dispose();
+ algorithm = new RSACryptoServiceProvider(2048);
+ }
+#endif
+
+ if (algorithm.KeySize < 2048) {
+ throw new InvalidOperationException("The ephemeral key generation failed.");
+ }
+
+ // Note: the RSA instance cannot be flowed as-is due to a bug in IdentityModel that disposes
+ // the underlying algorithm when it can be cast to RSACryptoServiceProvider. To work around
+ // this bug, the RSA public/private parameters are manually exported and re-imported when needed.
+ SecurityKey key;
+#if NET451
+ if (algorithm is RSACryptoServiceProvider) {
+ var parameters = algorithm.ExportParameters(includePrivateParameters: true);
+ key = new RsaSecurityKey(parameters);
+
+ // Dispose the algorithm instance.
+ algorithm.Dispose();
+ }
+
+ else {
+#endif
+ key = new RsaSecurityKey(algorithm);
+#if NET451
+ }
+#endif
+
+ return Configure(options => options.SigningCredentials.AddKey(key));
+ }
+
///
/// Registers a used to sign the tokens issued by OpenIddict.
///
diff --git a/src/OpenIddict.Core/OpenIddictExtensions.cs b/src/OpenIddict.Core/OpenIddictExtensions.cs
index 8581232b..0a84da88 100644
--- a/src/OpenIddict.Core/OpenIddictExtensions.cs
+++ b/src/OpenIddict.Core/OpenIddictExtensions.cs
@@ -93,6 +93,12 @@ namespace Microsoft.AspNetCore.Builder {
options.Cache = app.ApplicationServices.GetRequiredService();
}
+ if (options.SigningCredentials.Count == 0) {
+ throw new InvalidOperationException("At least one signing key must be registered. Consider registering a X.509 " +
+ "certificate using 'services.AddOpenIddict().AddSigningCertificate()' or call " +
+ "'services.AddOpenIddict().AddEphemeralSigningKey()' to use an ephemeral key.");
+ }
+
// Ensure at least one flow has been enabled.
if (options.GrantTypes.Count == 0) {
throw new InvalidOperationException("At least one OAuth2/OpenID Connect flow must be enabled.");