diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs index 7d3e3f63..9c6a1f60 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs @@ -118,6 +118,12 @@ public static partial class OpenIddictClientWebIntegrationHandlers request.Headers.Add("X-API-Key", settings.ApplicationKey); } + // Etsy requires sending the client identifier 'client_id' gotten from Authorization Code exchange aka x-api-key in the Headers (AttachAccessTokenParameter sets Authorization Bearer header already by default). + else if (context.Registration.ProviderType is ProviderTypes.Etsy) + { + request.Headers.Add("x-api-key", context.Registration.ClientId); + } + // Notion requires sending an explicit API version (which is statically set // to the last version known to be supported by the OpenIddict integration). else if (context.Registration.ProviderType is ProviderTypes.Notion) diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs index c1f6c4a6..8870917e 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs @@ -1044,6 +1044,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers left : new Uri("https://api.dailymotion.com/user", UriKind.Absolute), right: new Uri(identifier, UriKind.Relative)), + // Etsy's userinfo endpoint requires sending the user identifier in the URI path, which can be gotten from one of the tokens returned by the Token endpoint. + ProviderTypes.Etsy when (string?) context.TokenResponse?["access_token"] is string accessToken + && accessToken.Split(['.'],3).First() is string userId // TODO: Check if string type is correct because Etsy Reference states for this as Path Parameter https://developers.etsy.com/documentation/reference#operation/getUser + => OpenIddictHelpers.CreateAbsoluteUri( + left : new Uri("https://openapi.etsy.com/v3/application/users/", UriKind.Absolute), + right: new Uri(userId, UriKind.Relative)), + // HubSpot doesn't have a static userinfo endpoint but allows retrieving basic information // by using an access token info endpoint that requires sending the token in the URI path. ProviderTypes.HubSpot when @@ -1401,6 +1408,9 @@ public static partial class OpenIddictClientWebIntegrationHandlers ?.Select(parameter => (string?) parameter["email"]) ?.FirstOrDefault(), + // Etsy returns the email address as a custom "primary_email" node: + ProviderTypes.Etsy => (string?) context.UserInfoResponse?["primary_email"], + // HubSpot returns the email address as a custom "user" node: ProviderTypes.HubSpot => (string?) context.UserInfoResponse?["user"], @@ -1436,7 +1446,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers => (string?) context.UserInfoResponse?["username"], // These providers don't return a username so one is created using the "first_name" and "last_name" nodes: - ProviderTypes.Basecamp or ProviderTypes.Harvest or ProviderTypes.VkId + ProviderTypes.Basecamp or ProviderTypes.Etsy or ProviderTypes.Harvest or ProviderTypes.VkId when context.UserInfoResponse?.HasParameter("first_name") is true && context.UserInfoResponse?.HasParameter("last_name") is true => $"{(string?) context.UserInfoResponse?["first_name"]} {(string?) context.UserInfoResponse?["last_name"]}", @@ -1514,9 +1524,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers context.MergedPrincipal.SetClaim(ClaimTypes.NameIdentifier, issuer: issuer, value: context.Registration.ProviderType switch { // These providers return the user identifier as a custom "user_id" node: - ProviderTypes.Amazon or ProviderTypes.HubSpot or - ProviderTypes.StackExchange or ProviderTypes.Typeform or - ProviderTypes.VkId + ProviderTypes.Amazon or ProviderTypes.Etsy or + ProviderTypes.HubSpot or ProviderTypes.StackExchange or + ProviderTypes.Typeform or ProviderTypes.VkId + => (string?) context.UserInfoResponse?["user_id"], // ArcGIS and Trakt don't return a user identifier and require using the username as the identifier: diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml index c2ae4645..f046a117 100644 --- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml +++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml @@ -766,6 +766,44 @@ + + + + + + + + + + + + + + + + + + + + + + +