Skip to content

Commit ef8871b

Browse files
authored
Add osu! to the list of supported providers
1 parent 3815289 commit ef8871b

File tree

2 files changed

+92
-13
lines changed

2 files changed

+92
-13
lines changed

src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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:

src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,39 @@
17471747
ConfigurationEndpoint="https://api.orange.com/openidconnect/fr/v1/.well-known/openid-configuration" />
17481748
</Provider>
17491749

1750+
<!--
1751+
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
1752+
██ ▄▄▄ ██ ▄▄▄ ██ ██ ██ ██
1753+
██ ███ ██▄▄▄▀▀██ ██ ██ ██
1754+
██ ▀▀▀ ██ ▀▀▀ ██▄▀▀▄██▀██
1755+
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
1756+
-->
1757+
1758+
<Provider Name="Osu" DisplayName="osu!" Id="924114e6-6334-4124-bbf9-46cd5458da25"
1759+
Documentation="https://osu.ppy.sh/docs/index.html#authentication">
1760+
<Environment Issuer="https://osu.ppy.sh/">
1761+
<!--
1762+
Note: the address of the userinfo endpoint is not set here but is dynamically computed based
1763+
on the game mode selected when triggering the authentication challenge. If no game mode was
1764+
explicitly set, the default endpoint (https://osu.ppy.sh/api/v2/me) is automatically used.
1765+
-->
1766+
1767+
<Configuration AuthorizationEndpoint="https://osu.ppy.sh/oauth/authorize"
1768+
TokenEndpoint="https://osu.ppy.sh/oauth/token">
1769+
<GrantType Value="authorization_code" />
1770+
<GrantType Value="client_credentials" />
1771+
<GrantType Value="refresh_token" />
1772+
</Configuration>
1773+
</Environment>
1774+
1775+
<Constant Class="GameModes" Value="osu" Name="Standard" />
1776+
<Constant Class="GameModes" Value="taiko" Name="Taiko" />
1777+
<Constant Class="GameModes" Value="fruits" Name="Catch" />
1778+
<Constant Class="GameModes" Value="mania" Name="Mania" />
1779+
1780+
<Property Name="GameMode" DictionaryKey=".game_mode" />
1781+
</Provider>
1782+
17501783
<!--
17511784
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
17521785
██ ▄▄ █ ▄▄▀█▄▄ ▄▄██ ▄▄▀██ ▄▄▄██ ▄▄▄ ██ ▀██ ██

0 commit comments

Comments
 (0)