diff --git a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs index ca877ff7..69abb53b 100644 --- a/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs +++ b/gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs @@ -862,6 +862,7 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using OpenIddict.Client; using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants; +using static OpenIddict.Extensions.OpenIddictHelpers; namespace OpenIddict.Client.WebIntegration; diff --git a/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs b/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs index ba666793..f340b18c 100644 --- a/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs +++ b/shared/OpenIddict.Extensions/Helpers/OpenIddictHelpers.cs @@ -178,6 +178,18 @@ internal static class OpenIddictHelpers => new(source ?? throw new ArgumentNullException(nameof(source)), comparer); #endif + /// + /// Computes an absolute URI from the specified and URIs. + /// Note: if the URI is already absolute, it is directly returned. + /// + /// The left part. + /// The right part. + /// An absolute URI from the specified and . + /// is not an absolute URI. + [return: NotNullIfNotNull(nameof(right))] + public static Uri? CreateAbsoluteUri(Uri? left, string? right) + => CreateAbsoluteUri(left, !string.IsNullOrEmpty(right) ? new Uri(right, UriKind.RelativeOrAbsolute) : null); + /// /// Computes an absolute URI from the specified and URIs. /// Note: if the URI is already absolute, it is directly returned. diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs index f4e9f173..3dbd2aab 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs @@ -389,6 +389,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers => new(context.Response["data"]?.GetNamedParameters() ?? throw new InvalidOperationException(SR.FormatID0334("data"))), + // Nextcloud returns a nested "data" object that is itself nested in a "ocs" node. + ProviderTypes.Nextcloud => new(context.Response["ocs"]?["data"]?.GetNamedParameters() ?? + throw new InvalidOperationException(SR.FormatID0334("ocs/data"))), + // ServiceChannel returns a nested "UserProfile" object. ProviderTypes.ServiceChannel => new(context.Response["UserProfile"]?.GetNamedParameters() ?? throw new InvalidOperationException(SR.FormatID0334("UserProfile"))), diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs index ee769934..0b5396bd 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs @@ -1039,6 +1039,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers // Mailchimp returns the username as a custom "accountname" node: ProviderTypes.Mailchimp => (string?) context.UserinfoResponse?["accountname"], + // Nextcloud returns the username as a custom "displayname" or "display-name" node: + ProviderTypes.Nextcloud => (string?) context.UserinfoResponse?["displayname"] ?? + (string?) context.UserinfoResponse?["display-name"], + // Notion returns the username as a custom "bot/owner/user/name" node but // requires a special capability to access this node, that may not be present: ProviderTypes.Notion => (string?) context.UserinfoResponse?["bot"]?["owner"]?["user"]?["name"], @@ -1087,11 +1091,11 @@ public static partial class OpenIddictClientWebIntegrationHandlers => (string?) context.UserinfoResponse?["username"], // These providers return the user identifier as a custom "id" node: - ProviderTypes.Basecamp or ProviderTypes.Deezer or ProviderTypes.Discord or - ProviderTypes.Facebook or ProviderTypes.GitHub or ProviderTypes.Harvest or - ProviderTypes.Kroger or ProviderTypes.Lichess or ProviderTypes.Twitter or - ProviderTypes.Patreon or ProviderTypes.Reddit or ProviderTypes.Smartsheet or - ProviderTypes.Spotify or ProviderTypes.SubscribeStar + ProviderTypes.Basecamp or ProviderTypes.Deezer or ProviderTypes.Discord or + ProviderTypes.Facebook or ProviderTypes.GitHub or ProviderTypes.Harvest or + ProviderTypes.Kroger or ProviderTypes.Lichess or ProviderTypes.Nextcloud or + ProviderTypes.Patreon or ProviderTypes.Reddit or ProviderTypes.Smartsheet or + ProviderTypes.Spotify or ProviderTypes.SubscribeStar or ProviderTypes.Twitter => (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 a0d99abf..9b21c617 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml @@ -633,6 +633,29 @@ + + + + + + + + + + + + +