@@ -28,6 +28,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
2828 OverrideTokenEndpointClientAuthenticationMethod . Descriptor ,
2929 OverrideTokenEndpoint . Descriptor ,
3030 AttachNonStandardClientAssertionClaims . Descriptor ,
31+ OverrideScopes . Descriptor ,
3132 AttachAdditionalTokenRequestParameters . Descriptor ,
3233 AttachTokenRequestNonStandardClientCredentials . Descriptor ,
3334 AdjustRedirectUriInTokenRequest . Descriptor ,
@@ -603,6 +604,40 @@ public ValueTask HandleAsync(ProcessAuthenticationContext context)
603604 }
604605 }
605606
607+ /// <summary>
608+ /// Contains the logic responsible for overriding the scopes for the providers that require it.
609+ /// </summary>
610+ public sealed class OverrideScopes : IOpenIddictClientHandler < ProcessAuthenticationContext >
611+ {
612+ /// <summary>
613+ /// Gets the default descriptor definition assigned to this handler.
614+ /// </summary>
615+ public static OpenIddictClientHandlerDescriptor Descriptor { get ; }
616+ = OpenIddictClientHandlerDescriptor . CreateBuilder < ProcessAuthenticationContext > ( )
617+ . AddFilter < RequireTokenRequest > ( )
618+ . UseSingletonHandler < OverrideScopes > ( )
619+ . SetOrder ( AttachTokenRequestParameters . Descriptor . Order - 500 )
620+ . SetType ( OpenIddictClientHandlerType . BuiltIn )
621+ . Build ( ) ;
622+
623+ /// <inheritdoc />
624+ public ValueTask HandleAsync ( ProcessAuthenticationContext context )
625+ {
626+ ArgumentNullException . ThrowIfNull ( context ) ;
627+
628+ // osu! requires at least one scope to be set for client credentials grant, as tokens without
629+ // scopes are not valid. If no scope is explicitly specified, use the default value "public".
630+ if ( context . GrantType is GrantTypes . ClientCredentials &&
631+ context . Registration . ProviderType is ProviderTypes . Osu &&
632+ context . Scopes . Count is 0 )
633+ {
634+ context . Scopes . Add ( "public" ) ;
635+ }
636+
637+ return ValueTask . CompletedTask ;
638+ }
639+ }
640+
606641 /// <summary>
607642 /// Contains the logic responsible for attaching additional parameters
608643 /// to the token request for the providers that require it.
@@ -887,7 +922,7 @@ public ValueTask HandleAsync(ProcessAuthenticationContext context)
887922 // Note: these providers don't have a static userinfo endpoint attached to their configuration
888923 // so OpenIddict doesn't, by default, send a userinfo request. Since a dynamic endpoint is later
889924 // computed and attached to the context, the default value MUST be overridden to send a request.
890- ProviderTypes . Dailymotion or ProviderTypes . HubSpot or
925+ ProviderTypes . Dailymotion or ProviderTypes . HubSpot or ProviderTypes . Osu or
891926 ProviderTypes . SuperOffice or ProviderTypes . Zoho
892927 when context . GrantType is GrantTypes . AuthorizationCode or GrantTypes . DeviceCode or
893928 GrantTypes . Implicit or GrantTypes . Password or
@@ -1017,6 +1052,16 @@ ProviderTypes.HubSpot when
10171052 left : new Uri ( "https://api.hubapi.com/oauth/v1/access-tokens" , UriKind . Absolute ) ,
10181053 right : new Uri ( token , UriKind . Relative ) ) ,
10191054
1055+ // osu! supports specifying a game mode when querying the userinfo endpoint.
1056+ ProviderTypes . Osu => context . Properties . GetValueOrDefault ( Osu . Properties . GameMode ) switch
1057+ {
1058+ { Length : > 0 } mode => OpenIddictHelpers . CreateAbsoluteUri (
1059+ left : new Uri ( "https://osu.ppy.sh/api/v2/me" , UriKind . Absolute ) ,
1060+ right : new Uri ( mode , UriKind . Relative ) ) ,
1061+
1062+ _ => new Uri ( "https://osu.ppy.sh/api/v2/me" , UriKind . Absolute )
1063+ } ,
1064+
10201065 // SuperOffice doesn't expose a static OpenID Connect userinfo endpoint but offers an API whose
10211066 // absolute URI needs to be computed based on a special claim returned in the identity token.
10221067 ProviderTypes . SuperOffice when
@@ -1387,7 +1432,7 @@ public ValueTask HandleAsync(ProcessAuthenticationContext context)
13871432 ProviderTypes . ArcGisOnline or ProviderTypes . Dailymotion or ProviderTypes . DeviantArt or
13881433 ProviderTypes . Discord or ProviderTypes . Disqus or ProviderTypes . Kook or
13891434 ProviderTypes . Lichess or ProviderTypes . Mastodon or ProviderTypes . Mixcloud or
1390- ProviderTypes . Trakt or ProviderTypes . WordPress
1435+ ProviderTypes . Osu or ProviderTypes . Trakt or ProviderTypes . WordPress
13911436 => ( string ? ) context . UserInfoResponse ? [ "username" ] ,
13921437
13931438 // These providers don't return a username so one is created using the "first_name" and "last_name" nodes:
@@ -1482,17 +1527,18 @@ ProviderTypes.ArcGisOnline or ProviderTypes.Trakt
14821527 ProviderTypes . Atlassian => ( string ? ) context . UserInfoResponse ? [ "account_id" ] ,
14831528
14841529 // These providers return the user identifier as a custom "id" node:
1485- ProviderTypes . Airtable or ProviderTypes . Basecamp or ProviderTypes . Box or
1486- ProviderTypes . Dailymotion or ProviderTypes . Deezer or ProviderTypes . Discord or
1487- ProviderTypes . Disqus or ProviderTypes . Facebook or ProviderTypes . Figma or
1488- ProviderTypes . Genesys or ProviderTypes . Gitee or ProviderTypes . GitHub or
1489- ProviderTypes . Harvest or ProviderTypes . Kook or ProviderTypes . Kroger or
1490- ProviderTypes . Lichess or ProviderTypes . Linear or ProviderTypes . Mastodon or
1491- ProviderTypes . Meetup or ProviderTypes . Miro or ProviderTypes . Nextcloud or
1492- ProviderTypes . Patreon or ProviderTypes . Pipedrive or ProviderTypes . Reddit or
1493- ProviderTypes . Smartsheet or ProviderTypes . Spotify or ProviderTypes . SubscribeStar or
1494- ProviderTypes . Todoist or ProviderTypes . Twitter or ProviderTypes . Webflow or
1495- ProviderTypes . Weibo or ProviderTypes . Yandex or ProviderTypes . Zoom
1530+ ProviderTypes . Airtable or ProviderTypes . Basecamp or ProviderTypes . Box or
1531+ ProviderTypes . Dailymotion or ProviderTypes . Deezer or ProviderTypes . Discord or
1532+ ProviderTypes . Disqus or ProviderTypes . Facebook or ProviderTypes . Figma or
1533+ ProviderTypes . Genesys or ProviderTypes . Gitee or ProviderTypes . GitHub or
1534+ ProviderTypes . Harvest or ProviderTypes . Kook or ProviderTypes . Kroger or
1535+ ProviderTypes . Lichess or ProviderTypes . Linear or ProviderTypes . Mastodon or
1536+ ProviderTypes . Meetup or ProviderTypes . Miro or ProviderTypes . Nextcloud or
1537+ ProviderTypes . Osu or ProviderTypes . Patreon or ProviderTypes . Pipedrive or
1538+ ProviderTypes . Reddit or ProviderTypes . Smartsheet or ProviderTypes . Spotify or
1539+ ProviderTypes . SubscribeStar or ProviderTypes . Todoist or ProviderTypes . Twitter or
1540+ ProviderTypes . Webflow or ProviderTypes . Weibo or ProviderTypes . Yandex or
1541+ ProviderTypes . Zoom
14961542 => ( string ? ) context . UserInfoResponse ? [ "id" ] ,
14971543
14981544 // Bitbucket returns the user identifier as a custom "uuid" node:
0 commit comments