diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
index 437944d7..724e60b3 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
@@ -139,7 +139,6 @@ public class Worker : IHostedService
{
ApplicationType = ApplicationTypes.Web,
ClientId = "mvc",
- ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
ClientType = ClientTypes.Confidential,
ConsentType = ConsentTypes.Systematic,
DisplayName = "MVC client application",
@@ -165,6 +164,8 @@ public class Worker : IHostedService
"""))
}
},
+#else
+ ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
#endif
RedirectUris =
{
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
index c782c380..acd78464 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
@@ -36,6 +36,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
* Challenge processing:
*/
AttachNonDefaultDeviceAuthorizationEndpointClientAuthenticationMethod.Descriptor,
+ AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod.Descriptor,
/*
* Introspection processing:
@@ -290,7 +291,15 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
_ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
},
- Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported) switch
+ // Note: if the authorization server doesn't support the OpenIddict-specific
+ // "device_authorization_request_endpoint_auth_methods_supported" node,
+ // fall back to the "token_endpoint_auth_methods_supported" node,
+ // which is the same logic as for the pushed authorization endpoint.
+ Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported.Count switch
+ {
+ 0 => context.Configuration.TokenEndpointAuthMethodsSupported,
+ _ => context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported,
+ }) switch
{
// If a TLS client authentication certificate could be resolved and both the
// client and the server explicitly support tls_client_auth, always prefer it.
@@ -365,6 +374,137 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
}
}
+ ///
+ /// Contains the logic responsible for negotiating the best pushed authorization endpoint
+ /// client authentication method supported by both the client and the authorization server.
+ ///
+ public sealed class AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod : IOpenIddictClientHandler
+ {
+ private readonly IOptionsMonitor _options;
+
+ public AttachNonDefaultPushedAuthorizationEndpointClientAuthenticationMethod(
+ IOptionsMonitor options)
+ => _options = options ?? throw new ArgumentNullException(nameof(options));
+
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictClientHandlerDescriptor Descriptor { get; }
+ = OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .AddFilter()
+ .UseSingletonHandler()
+ .SetOrder(AttachPushedAuthorizationEndpointClientAuthenticationMethod.Descriptor.Order - 500)
+ .SetType(OpenIddictClientHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessChallengeContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ // If an explicit client authentication method was attached, don't overwrite it.
+ if (!string.IsNullOrEmpty(context.PushedAuthorizationEndpointClientAuthenticationMethod))
+ {
+ return default;
+ }
+
+ context.PushedAuthorizationEndpointClientAuthenticationMethod = (
+ // Note: if client authentication methods are explicitly listed in the client registration, only use
+ // the client authentication methods that are both listed and enabled in the global client options.
+ // Otherwise, always default to the client authentication methods that have been enabled globally.
+ Client: context.Registration.ClientAuthenticationMethods.Count switch
+ {
+ 0 => context.Options.ClientAuthenticationMethods as ICollection,
+ _ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
+ },
+
+ // Note: if the authorization server doesn't support the OpenIddict-specific
+ // "pushed_authorization_request_endpoint_auth_methods_supported" node, fall back to
+ // the "token_endpoint_auth_methods_supported" node, as required by the specification.
+ //
+ // See https://datatracker.ietf.org/doc/html/rfc9126#section-2 for more information.
+ Server: context.Configuration.PushedAuthorizationEndpointAuthMethodsSupported.Count switch
+ {
+ 0 => context.Configuration.TokenEndpointAuthMethodsSupported,
+ _ => context.Configuration.PushedAuthorizationEndpointAuthMethodsSupported,
+ }) switch
+ {
+ // If a TLS client authentication certificate could be resolved and both the
+ // client and the server explicitly support tls_client_auth, always prefer it.
+ ({ Count: > 0 } client, { Count: > 0 } server) when
+ client.Contains(ClientAuthenticationMethods.TlsClientAuth) &&
+ server.Contains(ClientAuthenticationMethods.TlsClientAuth) &&
+ (context.Configuration.MtlsPushedAuthorizationEndpoint ?? context.Configuration.PushedAuthorizationEndpoint) is Uri endpoint &&
+ string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
+ _options.CurrentValue.TlsClientAuthenticationCertificateSelector(context.Registration) is not null
+ => ClientAuthenticationMethods.TlsClientAuth,
+
+ // If a self-signed TLS client authentication certificate could be resolved and both
+ // the client and the server explicitly support self_signed_tls_client_auth, use it.
+ ({ Count: > 0 } client, { Count: > 0 } server) when
+ client.Contains(ClientAuthenticationMethods.SelfSignedTlsClientAuth) &&
+ server.Contains(ClientAuthenticationMethods.SelfSignedTlsClientAuth) &&
+ (context.Configuration.MtlsPushedAuthorizationEndpoint ?? context.Configuration.PushedAuthorizationEndpoint) is Uri endpoint &&
+ string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) &&
+ _options.CurrentValue.SelfSignedTlsClientAuthenticationCertificateSelector(context.Registration) is not null
+ => ClientAuthenticationMethods.SelfSignedTlsClientAuth,
+
+ // If at least one asymmetric signing key was attached to the client registration
+ // and both the client and the server explicitly support private_key_jwt, use it.
+ ({ Count: > 0 } client, { Count: > 0 } server) when
+ client.Contains(ClientAuthenticationMethods.PrivateKeyJwt) &&
+ server.Contains(ClientAuthenticationMethods.PrivateKeyJwt) &&
+ context.Registration.SigningCredentials.Exists(static credentials => credentials.Key is AsymmetricSecurityKey)
+ => ClientAuthenticationMethods.PrivateKeyJwt,
+
+ // If a client secret was attached to the client registration and both the client and
+ // the server explicitly support client_secret_post, prefer it to basic authentication.
+ ({ Count: > 0 } client, { Count: > 0 } server) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
+ client.Contains(ClientAuthenticationMethods.ClientSecretPost) &&
+ server.Contains(ClientAuthenticationMethods.ClientSecretPost)
+ => ClientAuthenticationMethods.ClientSecretPost,
+
+ // The OAuth 2.0 specification recommends sending the client credentials using basic authentication.
+ // However, this authentication method is known to have severe compatibility/interoperability issues:
+ //
+ // - While restricted to clients that have been given a secret (i.e confidential clients) by the
+ // specification, basic authentication is also sometimes required by server implementations for
+ // public clients that don't have a client secret: in this case, an empty password is used and
+ // the client identifier is sent alone in the Authorization header (instead of being sent using
+ // the standard "client_id" parameter present in the request body).
+ //
+ // - While the OAuth 2.0 specification requires that the client credentials be formURL-encoded
+ // before being base64-encoded, many implementations are known to implement a non-standard
+ // encoding scheme, where neither the client_id nor the client_secret are formURL-encoded.
+ //
+ // To guarantee that the OpenIddict implementation can be used with most servers implementions,
+ // basic authentication is only used when a client secret is present and the server configuration
+ // doesn't list any supported client authentication method or doesn't support client_secret_post.
+ //
+ // If client_secret_post is not listed or if the server returned an empty methods list,
+ // client_secret_basic is always used, as it MUST be implemented by all OAuth 2.0 servers.
+ //
+ // See https://tools.ietf.org/html/rfc8414#section-2
+ // and https://tools.ietf.org/html/rfc6749#section-2.3.1 for more information.
+ ({ Count: > 0 } client, { Count: > 0 } server) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
+ client.Contains(ClientAuthenticationMethods.ClientSecretBasic) &&
+ server.Contains(ClientAuthenticationMethods.ClientSecretBasic)
+ => ClientAuthenticationMethods.ClientSecretBasic,
+
+ ({ Count: > 0 } client, { Count: 0 }) when !string.IsNullOrEmpty(context.Registration.ClientSecret) &&
+ client.Contains(ClientAuthenticationMethods.ClientSecretBasic)
+ => ClientAuthenticationMethods.ClientSecretBasic,
+
+ _ => null
+ };
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for negotiating the best introspection endpoint client
/// authentication method supported by both the client and the authorization server.
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
index fa6bbb4f..dc8691ca 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
@@ -5847,7 +5847,15 @@ public static partial class OpenIddictClientHandlers
_ => context.Options.ClientAuthenticationMethods.Intersect(context.Registration.ClientAuthenticationMethods, StringComparer.Ordinal).ToList()
},
- Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported) switch
+ // Note: if the authorization server doesn't support the OpenIddict-specific
+ // "device_authorization_request_endpoint_auth_methods_supported" node,
+ // fall back to the "token_endpoint_auth_methods_supported" node,
+ // which is the same logic as for the pushed authorization endpoint.
+ Server: context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported.Count switch
+ {
+ 0 => context.Configuration.TokenEndpointAuthMethodsSupported,
+ _ => context.Configuration.DeviceAuthorizationEndpointAuthMethodsSupported,
+ }) switch
{
// If at least one signing key was attached to the client registration and both
// the client and the server explicitly support private_key_jwt, always prefer it.
@@ -6163,9 +6171,8 @@ public static partial class OpenIddictClientHandlers
///
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
- .AddFilter()
.UseSingletonHandler()
- .SetOrder(AttachDeviceAuthorizationRequestParameters.Descriptor.Order + 1_000)
+ .SetOrder(AttachPushedAuthorizationRequestParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
index b132de94..266aaf5d 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
@@ -332,7 +332,8 @@ public static partial class OpenIddictServerHandlers
// By default, client assertions are not required, but they are extracted and validated if
// present and invalid client assertions are always automatically rejected by OpenIddict.
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
- OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
+ OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
+ OpenIddictServerEndpointType.Token
=> (true, false, true, true),
_ => (false, false, false, false)
@@ -483,7 +484,8 @@ public static partial class OpenIddictServerHandlers
(context.ClientAssertion, context.ClientAssertionType) = context.EndpointType switch
{
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
- OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
+ OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
+ OpenIddictServerEndpointType.Token
when context.ExtractClientAssertion
=> (context.Request.ClientAssertion, context.Request.ClientAssertionType),
@@ -1032,6 +1034,12 @@ public static partial class OpenIddictServerHandlers
case OpenIddictServerEndpointType.Revocation when context.Options.AcceptAnonymousClients:
case OpenIddictServerEndpointType.Token when context.Options.AcceptAnonymousClients:
return;
+
+ // Note: despite being conceptually similar to the token endpoint, the pushed authorization
+ // endpoint deliberately doesn't allow anonymous clients, as a client_id is always required
+ // for both regular authorization requests and pushed authorization requests.
+ //
+ // See https://datatracker.ietf.org/doc/html/rfc9126#section-2.1 for more information.
}
context.Logger.LogInformation(6220, SR.GetResourceString(SR.ID6220), Parameters.ClientId);
@@ -1063,7 +1071,8 @@ public static partial class OpenIddictServerHandlers
{
// For non-interactive endpoints, return "invalid_client" instead of "invalid_request".
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
- OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
+ OpenIddictServerEndpointType.PushedAuthorization or OpenIddictServerEndpointType.Revocation or
+ OpenIddictServerEndpointType.Token
=> Errors.InvalidClient,
_ => Errors.InvalidRequest
@@ -1117,7 +1126,6 @@ public static partial class OpenIddictServerHandlers
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or
- OpenIddictServerEndpointType.PushedAuthorization or
OpenIddictServerEndpointType.UserInfo)
{
return;
@@ -1227,7 +1235,6 @@ public static partial class OpenIddictServerHandlers
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or
- OpenIddictServerEndpointType.PushedAuthorization or
OpenIddictServerEndpointType.UserInfo)
{
return;
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs
index c80206e7..48a2df2b 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Authentication.cs
@@ -3214,6 +3214,130 @@ public abstract partial class OpenIddictServerIntegrationTests
Assert.Equal(SR.FormatID8000(SR.ID2029), response.ErrorUri);
}
+ [Fact]
+ public async Task ValidatePushedAuthorizationRequest_ClientSecretCannotBeUsedByPublicClients()
+ {
+ // Arrange
+ var application = new OpenIddictApplication();
+
+ var manager = CreateApplicationManager(mock =>
+ {
+ mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
+ .ReturnsAsync(application);
+
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+ });
+
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.Services.AddSingleton(manager);
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/connect/par", new OpenIddictRequest
+ {
+ ClientId = "Fabrikam",
+ ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
+ RedirectUri = "http://www.fabrikam.com/path",
+ ResponseType = ResponseTypes.Code
+ });
+
+ // Assert
+ Assert.Equal(Errors.InvalidClient, response.Error);
+ Assert.Equal(SR.FormatID2053(Parameters.ClientSecret), response.ErrorDescription);
+ Assert.Equal(SR.FormatID8000(SR.ID2053), response.ErrorUri);
+
+ Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()), Times.AtLeastOnce());
+ Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()), Times.Once());
+ }
+
+ [Fact]
+ public async Task ValidatePushedAuthorizationRequest_ClientSecretIsRequiredForNonPublicClients()
+ {
+ // Arrange
+ var application = new OpenIddictApplication();
+
+ var manager = CreateApplicationManager(mock =>
+ {
+ mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
+ .ReturnsAsync(application);
+
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(false);
+ });
+
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.Services.AddSingleton(manager);
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/connect/par", new OpenIddictRequest
+ {
+ ClientId = "Fabrikam",
+ ClientSecret = null,
+ RedirectUri = "http://www.fabrikam.com/path",
+ ResponseType = ResponseTypes.Code
+ });
+
+ // Assert
+ Assert.Equal(Errors.InvalidClient, response.Error);
+ Assert.Equal(SR.FormatID2054(Parameters.ClientSecret), response.ErrorDescription);
+ Assert.Equal(SR.FormatID8000(SR.ID2054), response.ErrorUri);
+
+ Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()), Times.AtLeastOnce());
+ Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()), Times.Once());
+ }
+
+ [Fact]
+ public async Task ValidatePushedAuthorizationRequest_RequestIsRejectedWhenClientCredentialsAreInvalid()
+ {
+ // Arrange
+ var application = new OpenIddictApplication();
+
+ var manager = CreateApplicationManager(mock =>
+ {
+ mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
+ .ReturnsAsync(application);
+
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(false);
+
+ mock.Setup(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny()))
+ .ReturnsAsync(false);
+ });
+
+ await using var server = await CreateServerAsync(options =>
+ {
+ options.Services.AddSingleton(manager);
+ });
+
+ await using var client = await server.CreateClientAsync();
+
+ // Act
+ var response = await client.PostAsync("/connect/par", new OpenIddictRequest
+ {
+ ClientId = "Fabrikam",
+ ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
+ RedirectUri = "http://www.fabrikam.com/path",
+ ResponseType = ResponseTypes.Code
+ });
+
+ // Assert
+ Assert.Equal(Errors.InvalidClient, response.Error);
+ Assert.Equal(SR.GetResourceString(SR.ID2055), response.ErrorDescription);
+ Assert.Equal(SR.FormatID8000(SR.ID2055), response.ErrorUri);
+
+ Mock.Get(manager).Verify(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()), Times.AtLeastOnce());
+ Mock.Get(manager).Verify(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()), Times.AtLeastOnce());
+ Mock.Get(manager).Verify(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny()), Times.Once());
+ }
+
[Fact]
public async Task ValidatePushedAuthorizationRequest_MissingRedirectUriCausesAnErrorForOpenIdRequests()
{
@@ -4186,7 +4310,7 @@ public abstract partial class OpenIddictServerIntegrationTests
});
// Assert
- Assert.Equal(Errors.InvalidRequest, response.Error);
+ Assert.Equal(Errors.InvalidClient, response.Error);
Assert.Equal(SR.FormatID2052(Parameters.ClientId), response.ErrorDescription);
Assert.Equal(SR.FormatID8000(SR.ID2052), response.ErrorUri);
@@ -4233,6 +4357,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4274,6 +4401,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny()))
.ReturnsAsync(["rst:" + type]);
@@ -4337,6 +4467,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Confidential, It.IsAny()))
.ReturnsAsync(true);
+ mock.Setup(manager => manager.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny()))
.ReturnsAsync([]);
});
@@ -4352,6 +4485,7 @@ public abstract partial class OpenIddictServerIntegrationTests
var response = await client.PostAsync("/connect/par", new OpenIddictRequest
{
ClientId = "Fabrikam",
+ ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
Nonce = "n-0S6_WzA2Mj",
RedirectUri = "http://www.fabrikam.com/path",
ResponseType = type,
@@ -4378,6 +4512,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4453,6 +4590,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4510,6 +4650,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4560,6 +4703,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.GetPermissionsAsync(application, It.IsAny()))
.ReturnsAsync(["rst:" + type]);
@@ -4617,6 +4763,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4667,6 +4816,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(false);
});
@@ -4706,6 +4858,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4762,6 +4917,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4814,6 +4972,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4860,6 +5021,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4914,6 +5078,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -4968,6 +5135,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);
@@ -5137,6 +5307,9 @@ public abstract partial class OpenIddictServerIntegrationTests
mock.Setup(manager => manager.FindByClientIdAsync("Fabrikam", It.IsAny()))
.ReturnsAsync(application);
+ mock.Setup(manager => manager.HasClientTypeAsync(application, ClientTypes.Public, It.IsAny()))
+ .ReturnsAsync(true);
+
mock.Setup(manager => manager.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny()))
.ReturnsAsync(true);