diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
index 544facdd..ffe5bb28 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
@@ -29,6 +29,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
OverrideValidatedBackchannelTokens.Descriptor,
DisableBackchannelIdentityTokenNonceValidation.Descriptor,
OverrideUserinfoEndpoint.Descriptor,
+ DisableUserinfoRetrieval.Descriptor,
DisableUserinfoValidation.Descriptor,
AttachAdditionalUserinfoRequestParameters.Descriptor,
PopulateUserinfoTokenPrincipalFromTokenResponse.Descriptor,
@@ -451,6 +452,59 @@ public static partial class OpenIddictClientWebIntegrationHandlers
}
}
+ ///
+ /// Contains the logic responsible for disabling the userinfo retrieval for the providers that require it.
+ ///
+ public sealed class DisableUserinfoRetrieval : IOpenIddictClientHandler
+ {
+ ///
+ /// Gets the default descriptor definition assigned to this handler.
+ ///
+ public static OpenIddictClientHandlerDescriptor Descriptor { get; }
+ = OpenIddictClientHandlerDescriptor.CreateBuilder()
+ .UseSingletonHandler()
+ .SetOrder(EvaluateUserinfoRequest.Descriptor.Order + 250)
+ .SetType(OpenIddictClientHandlerType.BuiltIn)
+ .Build();
+
+ ///
+ public ValueTask HandleAsync(ProcessAuthenticationContext context)
+ {
+ if (context is null)
+ {
+ throw new ArgumentNullException(nameof(context));
+ }
+
+ context.SendUserinfoRequest = context.Registration.ProviderName switch
+ {
+ // Note: the frontchannel or backchannel access tokens returned by Azure AD when a
+ // Xbox scope is requested cannot be used with the userinfo endpoint as they use a
+ // legacy format that is not supported by the Azure AD userinfo implementation.
+ //
+ // To work around this limitation, userinfo retrieval is disabled when a Xbox scope is requested.
+ Providers.Microsoft => context.GrantType switch
+ {
+ GrantTypes.AuthorizationCode or GrantTypes.Implicit when
+ context.StateTokenPrincipal is ClaimsPrincipal principal &&
+ principal.HasClaim(static claim =>
+ claim.Type is Claims.Private.Scope &&
+ claim.Value.StartsWith("XboxLive.", StringComparison.OrdinalIgnoreCase))
+ => false,
+
+ GrantTypes.DeviceCode or GrantTypes.RefreshToken when
+ context.Scopes.Any(static scope => scope.StartsWith("XboxLive.", StringComparison.OrdinalIgnoreCase))
+ => false,
+
+ _ => context.SendUserinfoRequest
+ },
+
+ _ => context.SendUserinfoRequest
+ };
+
+ return default;
+ }
+ }
+
///
/// Contains the logic responsible for disabling the userinfo validation for the providers that require it.
///
@@ -462,7 +516,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder()
.UseSingletonHandler()
- .SetOrder(EvaluateUserinfoRequest.Descriptor.Order + 500)
+ .SetOrder(DisableUserinfoRetrieval.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();