diff --git a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs
index 8b02c66d..56e96938 100644
--- a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs
+++ b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs
@@ -70,8 +70,8 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder
/// Enables the {{ provider.display_name }} integration and registers the associated services in the DI container.
{{~ if provider.documentation ~}}
/// For more information, read the documentation.
- ///
{{~ end ~}}
+ ///
/// This extension can be safely called multiple times.
/// The instance.
public OpenIddictClientWebIntegrationBuilder.{{ provider.name }} Use{{ provider.name }}()
@@ -92,8 +92,8 @@ public sealed partial class OpenIddictClientWebIntegrationBuilder
/// Enables the {{ provider.display_name }} integration and registers the associated services in the DI container.
{{~ if provider.documentation ~}}
/// For more information, read the documentation.
- ///
{{~ end ~}}
+ ///
/// This extension can be safely called multiple times.
/// The delegate used to configure the OpenIddict/{{ provider.display_name }} options.
/// The instance.
diff --git a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Exchange.cs b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Exchange.cs
index a000101d..e4740290 100644
--- a/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Exchange.cs
+++ b/src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Exchange.cs
@@ -91,7 +91,8 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
//
// See https://tools.ietf.org/html/rfc8414#section-2
// and https://tools.ietf.org/html/rfc6749#section-2.3.1 for more information.
- if (!string.IsNullOrEmpty(context.Request.ClientId) &&
+ if (request.Headers.Authorization is null &&
+ !string.IsNullOrEmpty(context.Request.ClientId) &&
!string.IsNullOrEmpty(context.Request.ClientSecret) &&
UseBasicAuthentication(context.Configuration))
{
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs
index cdeaf2ca..f3980929 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs
@@ -99,7 +99,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.Configuration.GrantTypesSupported.Add(GrantTypes.RefreshToken);
}
- else if (context.Registration.ProviderName is Providers.Cognito or Providers.Microsoft)
+ else if (context.Registration.ProviderName is Providers.Cognito or Providers.EpicGames or Providers.Microsoft)
{
context.Configuration.GrantTypesSupported.Add(GrantTypes.AuthorizationCode);
context.Configuration.GrantTypesSupported.Add(GrantTypes.ClientCredentials);
@@ -181,11 +181,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
- // While it is a recommended node, Xero doesn't include "scopes_supported" in its server
- // configuration and thus is treated as an OAuth 2.0-only provider by the OpenIddict client.
- //
+ // While it is a recommended node, some providers don't include "scopes_supported" in their
+ // configuration and thus are treated as OAuth 2.0-only providers by the OpenIddict client.
// To avoid that, the "openid" scope is manually added to indicate OpenID Connect is supported.
- if (context.Registration.ProviderName is Providers.Xero)
+ if (context.Registration.ProviderName is Providers.EpicGames or Providers.Xero)
{
context.Configuration.ScopesSupported.Add(Scopes.OpenId);
}
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs
index d85a3464..5da911b1 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Exchange.cs
@@ -49,7 +49,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.AddFilter()
.UseSingletonHandler()
- .SetOrder(AttachBasicAuthenticationCredentials.Descriptor.Order + 500)
+ .SetOrder(AttachBasicAuthenticationCredentials.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@@ -75,25 +75,40 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// These providers require using basic authentication to flow the client_id
// for all types of client applications, even when there's no client_secret.
- //
- // Note: only cases where the client secret is null are handled here (scenarios
- // where the Authorization header includes a non-empty password are handled by
- // a generic handler in the OpenIddict.Client.SystemNetHttp integration package).
if (context.Registration.ProviderName is Providers.Reddit &&
- !string.IsNullOrEmpty(context.Request.ClientId) &&
- string.IsNullOrEmpty(context.Request.ClientSecret))
+ !string.IsNullOrEmpty(context.Request.ClientId))
{
- // Important: the client_id MUST be formURL-encoded before being base64-encoded.
+ // Important: the credentials MUST be formURL-encoded before being base64-encoded.
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(new StringBuilder()
.Append(EscapeDataString(context.Request.ClientId))
.Append(':')
+ .Append(EscapeDataString(context.Request.ClientSecret))
.ToString()));
// Attach the authorization header containing the client identifier to the HTTP request.
request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Basic, credentials);
- // Remove the client identifier from the request payload to ensure it's not sent twice.
- context.Request.ClientId = null;
+ // Remove the client credentials from the request payload to ensure they are not sent twice.
+ context.Request.ClientId = context.Request.ClientSecret = null;
+ }
+
+ // These providers don't implement the standard version of the client_secret_basic
+ // authentication method as they don't support formURL-encoding the client credentials.
+ else if (context.Registration.ProviderName is Providers.EpicGames &&
+ !string.IsNullOrEmpty(context.Request.ClientId) &&
+ !string.IsNullOrEmpty(context.Request.ClientSecret))
+ {
+ var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(new StringBuilder()
+ .Append(context.Request.ClientId)
+ .Append(':')
+ .Append(context.Request.ClientSecret)
+ .ToString()));
+
+ // Attach the authorization header containing the client identifier to the HTTP request.
+ request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Basic, credentials);
+
+ // Remove the client credentials from the request payload to ensure they are not sent twice.
+ context.Request.ClientId = context.Request.ClientSecret = null;
}
return default;
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
index 831335d6..94755cb5 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
@@ -238,6 +238,19 @@
+
+
+
+
+
+