diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
index 45d1cfd3..c5265080 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
@@ -28,6 +28,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
OverrideTokenEndpointClientAuthenticationMethod.Descriptor,
OverrideTokenEndpoint.Descriptor,
AttachNonStandardClientAssertionClaims.Descriptor,
+ OverrideScope.Descriptor,
AttachAdditionalTokenRequestParameters.Descriptor,
AttachTokenRequestNonStandardClientCredentials.Descriptor,
AdjustRedirectUriInTokenRequest.Descriptor,
@@ -621,6 +622,45 @@ public static partial class OpenIddictClientWebIntegrationHandlers
}
}
+ ///
+ /// Contains the logic responsible for overriding the scope to be attached
+ /// to the token request for the providers that require it.
+ ///
+ public sealed class OverrideScope : IOpenIddictClientHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictClientHandlerDescriptor Descriptor { get; }
+ = OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .AddFilter()
+ .UseSingletonHandler()
+ .SetOrder(AttachTokenRequestParameters.Descriptor.Order + 250)
+ .SetType(OpenIddictClientHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessAuthenticationContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ Debug.Assert(context.TokenRequest is not null, SR.GetResourceString(SR.ID4008));
+
+ // osu! requires that the scope must be "public" for client credentials
+ // grant, as other scopes have no meaningful effect.
+ if (context.GrantType is GrantTypes.ClientCredentials &&
+ context.Registration.ProviderType is ProviderTypes.Osu)
+ {
+ context.TokenRequest.Scope = "public";
+ }
+
+ return ValueTask.CompletedTask;
+ }
+ }
+
///
/// Contains the logic responsible for attaching additional parameters
/// to the token request for the providers that require it.
@@ -666,13 +706,6 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.TokenRequest.UserCode = code;
}
- // osu! requires the "public" scope for client credentials grant, as tokens without scopes are invalid.
- else if (context.GrantType is GrantTypes.ClientCredentials &&
- context.Registration.ProviderType is ProviderTypes.Osu)
- {
- context.TokenRequest.Scope = "public";
- }
-
// VK ID requires attaching a non-standard "device_id" parameter to all token requests.
//
// This parameter is either resolved from the authorization response (for the authorization
@@ -1445,7 +1478,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
ProviderTypes.ArcGisOnline or ProviderTypes.Dailymotion or ProviderTypes.DeviantArt or
ProviderTypes.Discord or ProviderTypes.Disqus or ProviderTypes.Kook or
ProviderTypes.Lichess or ProviderTypes.Mastodon or ProviderTypes.Mixcloud or
- ProviderTypes.Trakt or ProviderTypes.WordPress
+ ProviderTypes.Osu or ProviderTypes.Trakt or ProviderTypes.WordPress
=> (string?) context.UserInfoResponse?["username"],
// These providers don't return a username so one is created using the "first_name" and "last_name" nodes:
@@ -1540,17 +1573,18 @@ public static partial class OpenIddictClientWebIntegrationHandlers
ProviderTypes.Atlassian => (string?) context.UserInfoResponse?["account_id"],
// These providers return the user identifier as a custom "id" node:
- ProviderTypes.Airtable or ProviderTypes.Basecamp or ProviderTypes.Box or
- ProviderTypes.Dailymotion or ProviderTypes.Deezer or ProviderTypes.Discord or
- ProviderTypes.Disqus or ProviderTypes.Facebook or ProviderTypes.Figma or
- ProviderTypes.Genesys or ProviderTypes.Gitee or ProviderTypes.GitHub or
- ProviderTypes.Harvest or ProviderTypes.Kook or ProviderTypes.Kroger or
- ProviderTypes.Lichess or ProviderTypes.Linear or ProviderTypes.Mastodon or
- ProviderTypes.Meetup or ProviderTypes.Miro or ProviderTypes.Nextcloud or
- ProviderTypes.Patreon or ProviderTypes.Pipedrive or ProviderTypes.Reddit or
- ProviderTypes.Smartsheet or ProviderTypes.Spotify or ProviderTypes.SubscribeStar or
- ProviderTypes.Todoist or ProviderTypes.Twitter or ProviderTypes.Webflow or
- ProviderTypes.Weibo or ProviderTypes.Yandex or ProviderTypes.Zoom
+ ProviderTypes.Airtable or ProviderTypes.Basecamp or ProviderTypes.Box or
+ ProviderTypes.Dailymotion or ProviderTypes.Deezer or ProviderTypes.Discord or
+ ProviderTypes.Disqus or ProviderTypes.Facebook or ProviderTypes.Figma or
+ ProviderTypes.Genesys or ProviderTypes.Gitee or ProviderTypes.GitHub or
+ ProviderTypes.Harvest or ProviderTypes.Kook or ProviderTypes.Kroger or
+ ProviderTypes.Lichess or ProviderTypes.Linear or ProviderTypes.Mastodon or
+ ProviderTypes.Meetup or ProviderTypes.Miro or ProviderTypes.Nextcloud or
+ ProviderTypes.Osu or ProviderTypes.Patreon or ProviderTypes.Pipedrive or
+ ProviderTypes.Reddit or ProviderTypes.Smartsheet or ProviderTypes.Spotify or
+ ProviderTypes.SubscribeStar or ProviderTypes.Todoist or ProviderTypes.Twitter or
+ ProviderTypes.Webflow or ProviderTypes.Weibo or ProviderTypes.Yandex or
+ ProviderTypes.Zoom
=> (string?) context.UserInfoResponse?["id"],
// Bitbucket returns the user identifier as a custom "uuid" node:
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
index 20dc4e13..c3fe7c59 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
@@ -1765,15 +1765,16 @@
+
-
-
-
-
+
+
+
+
+ Description="The game mode to retrieve statistics for (e.g., 'osu', 'taiko', 'fruits', 'mania'). User default mode will be used if not specified" />