diff --git a/src/OpenIddict.Abstractions/OpenIddictResources.resx b/src/OpenIddict.Abstractions/OpenIddictResources.resx
index e8d130a8..c467b571 100644
--- a/src/OpenIddict.Abstractions/OpenIddictResources.resx
+++ b/src/OpenIddict.Abstractions/OpenIddictResources.resx
@@ -1572,6 +1572,9 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
At least one subject type must be supported.
+
+ A configuration manager must be attached to the client registration to be able to resolve the server configuration.
+
The security token is missing.
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs
index 90acc576..17b39ad3 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs
@@ -305,7 +305,8 @@ public static partial class OpenIddictClientHandlers
// If validation failed because of an unrecognized key identifier and a client
// registration is available, inform the configuration manager that the configuration
// MAY have be refreshed by sending a new discovery request to the authorization server.
- if (context.Registration is not null && result.Exception is SecurityTokenSignatureKeyNotFoundException)
+ if (result.Exception is SecurityTokenSignatureKeyNotFoundException &&
+ context.Registration.ConfigurationManager is not null)
{
context.Registration.ConfigurationManager.RequestRefresh();
}
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
index d065c756..faef0475 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
@@ -423,26 +423,34 @@ public static partial class OpenIddictClientHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0408));
}
- try
+ // Resolve and attach the server configuration to the context if none has been set already.
+ if (context.Configuration is null)
{
- // Resolve and attach the server configuration to the context if none has been set already.
- context.Configuration ??= await context.Registration.ConfigurationManager
- .GetConfigurationAsync(context.CancellationToken)
- .WaitAsync(context.CancellationToken) ??
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
- }
+ if (context.Registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
- catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
- exception is not OperationCanceledException)
- {
- context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
+ try
+ {
+ context.Configuration = await context.Registration.ConfigurationManager
+ .GetConfigurationAsync(context.CancellationToken)
+ .WaitAsync(context.CancellationToken) ??
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
+ }
- context.Reject(
- error: Errors.ServerError,
- description: SR.GetResourceString(SR.ID2170),
- uri: SR.FormatID8000(SR.ID2170));
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
+ exception is not OperationCanceledException)
+ {
+ context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
- return;
+ context.Reject(
+ error: Errors.ServerError,
+ description: SR.GetResourceString(SR.ID2170),
+ uri: SR.FormatID8000(SR.ID2170));
+
+ return;
+ }
}
// Ensure the selected grant type, if explicitly set, is listed as supported in the configuration.
@@ -1019,28 +1027,37 @@ public static partial class OpenIddictClientHandlers
// Note: if the static registration cannot be found in the options, this may indicate
// the client was removed after the authorization dance started and thus, can no longer
// be used to authenticate users. In this case, throw an exception to abort the flow.
- context.Registration = await _service.GetClientRegistrationByIdAsync(context.RegistrationId, context.CancellationToken);
+ context.Registration ??= await _service.GetClientRegistrationByIdAsync(context.RegistrationId, context.CancellationToken);
- try
+ // Resolve and attach the server configuration to the context if none has been set already.
+ if (context.Configuration is null)
{
- // Resolve and attach the server configuration to the context.
- context.Configuration = await context.Registration.ConfigurationManager
- .GetConfigurationAsync(context.CancellationToken)
- .WaitAsync(context.CancellationToken) ??
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
- }
+ if (context.Registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
- catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
- exception is not OperationCanceledException)
- {
- context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
+ try
+ {
+ // Resolve and attach the server configuration to the context.
+ context.Configuration = await context.Registration.ConfigurationManager
+ .GetConfigurationAsync(context.CancellationToken)
+ .WaitAsync(context.CancellationToken) ??
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
+ }
- context.Reject(
- error: Errors.ServerError,
- description: SR.GetResourceString(SR.ID2170),
- uri: SR.FormatID8000(SR.ID2170));
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
+ exception is not OperationCanceledException)
+ {
+ context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
- return;
+ context.Reject(
+ error: Errors.ServerError,
+ description: SR.GetResourceString(SR.ID2170),
+ uri: SR.FormatID8000(SR.ID2170));
+
+ return;
+ }
}
}
}
@@ -4209,26 +4226,34 @@ public static partial class OpenIddictClientHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0408));
}
- try
+ // Resolve and attach the server configuration to the context if none has been set already.
+ if (context.Configuration is null)
{
- // Resolve and attach the server configuration to the context if none has been set already.
- context.Configuration ??= await context.Registration.ConfigurationManager
- .GetConfigurationAsync(context.CancellationToken)
- .WaitAsync(context.CancellationToken) ??
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
- }
+ if (context.Registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
- catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
- exception is not OperationCanceledException)
- {
- context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
+ try
+ {
+ context.Configuration = await context.Registration.ConfigurationManager
+ .GetConfigurationAsync(context.CancellationToken)
+ .WaitAsync(context.CancellationToken) ??
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
+ }
- context.Reject(
- error: Errors.ServerError,
- description: SR.GetResourceString(SR.ID2170),
- uri: SR.FormatID8000(SR.ID2170));
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
+ exception is not OperationCanceledException)
+ {
+ context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
- return;
+ context.Reject(
+ error: Errors.ServerError,
+ description: SR.GetResourceString(SR.ID2170),
+ uri: SR.FormatID8000(SR.ID2170));
+
+ return;
+ }
}
}
}
@@ -5852,26 +5877,34 @@ public static partial class OpenIddictClientHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0408));
}
- try
+ // Resolve and attach the server configuration to the context if none has been set already.
+ if (context.Configuration is null)
{
- // Resolve and attach the server configuration to the context if none has been set already.
- context.Configuration ??= await context.Registration.ConfigurationManager
- .GetConfigurationAsync(context.CancellationToken)
- .WaitAsync(context.CancellationToken) ??
- throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
- }
+ if (context.Registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
- catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
- exception is not OperationCanceledException)
- {
- context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
+ try
+ {
+ context.Configuration = await context.Registration.ConfigurationManager
+ .GetConfigurationAsync(context.CancellationToken)
+ .WaitAsync(context.CancellationToken) ??
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0140));
+ }
- context.Reject(
- error: Errors.ServerError,
- description: SR.GetResourceString(SR.ID2170),
- uri: SR.FormatID8000(SR.ID2170));
+ catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception) &&
+ exception is not OperationCanceledException)
+ {
+ context.Logger.LogError(exception, SR.GetResourceString(SR.ID6219));
- return;
+ context.Reject(
+ error: Errors.ServerError,
+ description: SR.GetResourceString(SR.ID2170),
+ uri: SR.FormatID8000(SR.ID2170));
+
+ return;
+ }
}
}
}
diff --git a/src/OpenIddict.Client/OpenIddictClientRegistration.cs b/src/OpenIddict.Client/OpenIddictClientRegistration.cs
index 980413bb..1fbe91cb 100644
--- a/src/OpenIddict.Client/OpenIddictClientRegistration.cs
+++ b/src/OpenIddict.Client/OpenIddictClientRegistration.cs
@@ -143,7 +143,7 @@ public sealed class OpenIddictClientRegistration
///
/// Gets or sets the configuration manager used to retrieve and cache the server configuration.
///
- public IConfigurationManager ConfigurationManager { get; set; } = default!;
+ public IConfigurationManager? ConfigurationManager { get; set; }
///
/// Gets or sets the URI of the configuration endpoint exposed by the server.
diff --git a/src/OpenIddict.Client/OpenIddictClientService.cs b/src/OpenIddict.Client/OpenIddictClientService.cs
index 494cfe20..04955632 100644
--- a/src/OpenIddict.Client/OpenIddictClientService.cs
+++ b/src/OpenIddict.Client/OpenIddictClientService.cs
@@ -154,6 +154,11 @@ public sealed class OpenIddictClientService
}
var registration = await GetClientRegistrationAsync(issuer, cancellationToken);
+ if (registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
+
return await registration.ConfigurationManager
.GetConfigurationAsync(cancellationToken)
.WaitAsync(cancellationToken) ??
@@ -182,6 +187,11 @@ public sealed class OpenIddictClientService
}
var registration = await GetClientRegistrationAsync(provider, cancellationToken);
+ if (registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
+
return await registration.ConfigurationManager
.GetConfigurationAsync(cancellationToken)
.WaitAsync(cancellationToken) ??
@@ -207,6 +217,11 @@ public sealed class OpenIddictClientService
}
var registration = await GetClientRegistrationByIdAsync(identifier, cancellationToken);
+ if (registration.ConfigurationManager is null)
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0422));
+ }
+
return await registration.ConfigurationManager
.GetConfigurationAsync(cancellationToken)
.WaitAsync(cancellationToken) ??