Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(etsy): Add Etsy Web Provider#2398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
DevTKSS wants to merge6 commits intoopeniddict:dev
base:dev
Choose a base branch
Loading
fromDevTKSS:feat/add-etsy-web-provider

Conversation

@DevTKSS
Copy link

@DevTKSSDevTKSS commentedNov 24, 2025
edited
Loading

This PR should be adding Etsy as OAuth2 Web Provider

PR Requires help

Known Problems / open tasks / decisions

  • Evaluate changing the setting for theUserInfoEndpoint in Etsy Provider:
    • fromgetMe, which would be commonly the url we are used to call for this task/users/me but does not return regular User Information we might be expecting like a Name or email

      • mapshop_id Parameter returned by this endpoint -> if we use this Endpoint we only return theuser_id and theshop_id will be automatically returned somewhere/somehow 🤷
        switched to getUser, so if this doesn't get decided to get reverted, we dont care aboutshop_id
    • togetUser Endpoint which returns those parameters but doesn't need additional Mapping in e.g.MapNonStandardResponseParameters()

    • required additional scopeemail_r which isnot guaranteed to be granted by the consumer!
      Referring to the Endpoint description

      Retrieves a user profile based on a unique user ID. Access is limited to profiles of the authenticated user or linked buyers. For the primary_email field, specific app-based permissions are required and granted case-by-case.

    • json response parameters (Claims to be added?):

      • user_id
      • primary_email
      • first_name
      • last_name
      • image_url_75x75
    • Path Parameters:

      • user_id (Type:<int64>) - Please check out the TODO's inUserInfo and Handler Claims added for this. Not sure if this is now redundant and we can remove most of them fromUserInfo Partial Class 🤔
    • Uri:https://openapi.etsy.com/v3/application/users/{user_id} - Removed from xml file, now using OverrideUserInfoEndpoint

    • Maybe we need to add Etsy Provider to theOverrideUserInfoRetrieval List here too, please check for this 👍

Tip

Theuser_id parameter canalso be extracted from theaccess_token orrefresh_token parameter after Authentication Code Exchange, not only by calling thegetMe Endpoint, which provides us the uniqueshop_id parameter used for other endpoints
Etsy Docs provided Sample response after code exchange:

{"access_token":"12345678.O1zLuwveeKjpIqCQFfmR-PaMMpBmagH6DljRAkK9qt05OtRKiANJOyZlMx3WQ_o2FdComQGuoiAWy3dxyGI4Ke_76PR","token_type":"Bearer","expires_in":3600,"refresh_token":"12345678.JNGIJtvLmwfDMhlYoOJl8aLR1BWottyHC6yhNcET-eC7RogSR5e1GTIXGrgrelWZalvh3YvvyLfKYYqvymd-u37Sjtx"}
  • Scopes Are not be generated inScopesSupported Collection in the Configuration, not even the default ones (?)
    image

    imageimage

Other Points to check

Additional Information for Reviewer

  • Setting up Header + Authorization Header appropriately

  • Etsy does not make use of theShared Secret aka Client Secret, but the Registration provides one, the client is treatened as public client + requires interactive, no implicit or non-interactive flow is supported!

    • Generated Configuration states that we support this for Device, Introspection, Revocation Endpoint Auth Methods, which areNOT supported at all from this API 🤔
      image
  • Do the both App Registration kinds in Etsy require different Envirionments?
    both are using same uri's

    • Personal Access
    • Commercial Access
  • Etsy Auth does not support a Logout as such, but the generator seems to accepts a Logout Uri?
    image

@kevinchalet could you please help me set this up correctly?

@kevinchalet
Copy link
Member

Hey,

Thanks for your PR!

Add thegetUser Endpoint Call, to get complete expected UserInfo. This is no contained getMe response parameter then instead requires a 2nd call!

Only a single userinfo call made by OpenIddict is supported: any additional API call is the responsibility of the developers, who can implement that in their authorization controller (e.g to persist any additional information in the authentication cookie before it is returned).

How is the Provider Id meant to be generated? - gets linted, and GUID generator in VS2026 does not satisfy the requirements

It must be generated randomly. Make sure it respects the same exact format as other providers (no braces, all lowercase, etc.).

CodeChallengeMethod isstated to be required in Configuration tag, but gets linted.

When you have multiple nodes underConfiguration, make sure you list them in the alphabetical order. The schema warning should go away.

It did not get completly clear, how to add the shop_id Claim into the getMe (/users/me) User Info Endpoint Claim Context, so I was only able to add the Provider for the user_id registration here: src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

All the claims returned by the provider are returned by OpenIddict so you don't need to do anything special for thatshop_id thing. Only the user identifier/name/email claims get a special treatment and are mapped to their WS-Federation equivalent (BCLClaimTypes class) to make working with multiple providers (who all use their own non-standard claims) easier.

Secondary, the Header + Authorization Header Setup is not documented, please check if this is correct this way:
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs (see diff)
or if one of them is needed to be moved in another method.

We can't realistically list all the workarounds possible in the documentation (otherwise it would become unreadable 🤣). Luckily, most providers don't need to change that.

What you've done looks good 👍🏻

! Etsy does not make use of the Shared Secret aka Client Secret, but the Registration provides one, the client is treatened as public client + requires interactive, no implicit or non-interactive flow is supported!

That's fine: if the service doesn't currently support client authentication, the user will not have to callSetClientSecret() and no client secret will be sent. Should they add client support authentication support in the future, no change will be required on our side as all APIs will already be available to support that.

Does that require Environments to be defined for this? There is no Development Environment API in etsy.

If the URLs are exactly the same, then no, it's not necessary/useful. A singleProduction environment is always created by OpenIddict.

Hope I answered all your questions 😃

… AccessToken and call getUsers instead of getMechore: Add Claims for name and Email
…Endpoint for UserInfo, remove UserInfoEndpoint from settings as its now overriddenchore: Adjust Scopes Required state in Provider.xml
@DevTKSS
Copy link
Author

@kevinchalet I updated the OP above with Task bullet points, so you can see where are still open/unclear points 👍

When you have multiple nodes under Configuration, make sure you list them in the alphabetical order. The schema warning should go away.

thanks, worked 👍

possible a nice small information in docs would be good to add for future contributors? for example the current note could be considerable to be updated like this:

Note

When the provider is known to support Proof Key for Code Exchange (PKCE), a<CodeChallengeMethod> node MUST be added under<Configuration> to ensure the OpenIddict client will send appropriate code_challenge/code_challenge_method parameters:
... Code Sample left out for brevity ...
In case you might need to add other tags likeGrantType's mentioned before, make sure to sort the nested Properties in ascending alphabetical order.

  • Changed the endpoint used for User Info call togetUser instead ofgetMe and extracting the requireduser_id from theaccess_token parameter, so we would be able to return actual expected User Info (updated/added on the OP List)

Referring to your response:

Only a single userinfo call made by OpenIddict is supported: any additional API call is the responsibility of the developers, who can implement that in their authorization controller (e.g to persist any additional information in the authentication cookie before it is returned).

@DevTKSSDevTKSS marked this pull request as ready for reviewNovember 25, 2025 18:03
@DevTKSS
Copy link
Author

DevTKSS commentedNov 25, 2025
edited
Loading

trying out in e.g. the OpenIdDict.Sandbox.Console.Client I would see the Scopes not beeing generated while we do list them in the xml file as something that should be fixed if possible. I am not really sure for what they chould otherwhile be meant when not giving us the option to get them generated as const string or similar while registration of the Provider in the end 🤔 maybe you can tell?

@kevinchalet Seems like something gets messed up with the Request 🤔
I did add the url defined in theAddRegistration( forhttps://localhost:44395/ in the valid callback url in my app registration at Etsy API, but while I am send successfully to the browser and can loop through social login, the redirect meant to be executed afterwards is failing, because from what I am seeing theredirect_url is loosing the 2nd4 at the start 🤔
(replaced client_id value with placeholder, I was able verify that this was correctly provided 👍 )

OpenIdDict.Sandbox.Console.Client
https://www.etsy.com/oauth/connect?client_id={correct-client-id}&redirect_uri=http%3A%2F%2Flocalhost%3A49152%2Fcallback%2Fetsy&response_type=code&scope=shops_r+email_r&code_challenge=R2Dn8pQSqYf_MfhgLG9pETvEvMTWzZuyIJ6qBBBwjw0&code_challenge_method=S256&state=8lUjo7nznfqFqpC_49AmhMtAQPl3TQqQZtAj8ezrh_U
image

What doesn't fit:

  • redirect_url should be something like this:https://localhost:44395/ +callback/etsy

Etsy Auth guide Reference for this:
https://developers.etsy.com/documentation/essentials/authentication#step-1-request-an-authorization-code

OpenIddict.Sandbox.AspNetCore.Client is failing too
https://www.etsy.com/oauth/connect?client_id={valid-client-id}&redirect_uri=https%3A%2F%2Flocalhost%3A44381%2Fcallback%2Fetsy&response_type=code&scope=shops_r%20email_r&code_challenge=NW7DOvyu4RVlls-C5PcJrToyzh5TG8GJJ8JswTSMMKY&code_challenge_method=S256&state=mxKc2tx6dlWcgvu9rm4Vp5hnY8AETJhryOwXqeLQbXQ
this would be a valid approach using 5001 port from the login page at etsy auth
https://www.etsy.com/oauth2/signin?from_page=%2Foauth%2Fconnect%3Fclient_id%3D{valid-client-id}%26scope%3Dshops_r%2520email_r%26response_type%3Dcode%26redirect_uri%3Dhttps%253A%252F%252Flocalhost%253A5001%252Fetsy%252Fcallback%26code_challenge%3DLVTddG56qoZT26KTP64y5r_hPuvwjmrEi-N7KHndslk%26code_challenge_method%3DS256%26state%3DCfDJ8Igeu-mhL-BPi5Zj_sG7stEdBFQEo3jyXbSAgBj4332XrgHlIftisfTb3XX49tGjjCpyxTrYGqrPlCNplqGEyKpeK27qLXvnPU0v2a1nKnSnYJ9fTg_zedqaWBB-RgrXf3aQ3hCOw7c2ttORzBeo3jL65UhabE4GyEEI9AYd2g6Hnhv5SiJAQ9hBiUNX37sMLlD9HD6Pn8QzTLPknZmukRy2ve0F3ZxEisbkYdHwID797cmD22veibPtGQikmBglZW572vCTCuzzJcBwBCvdOftxVEK3BygsiiogJHYA4Tax&lp=1&show_social_sign_in=1&is_from_etsyapp=0&initial_state=sign-in&client_id={valid-client-id}

as they are internally redirecting, the important thing to notice is that the port is completely provided after the%253A which seems to stand for the encoded: maybe. the CallbackPath for that sample has been/etsy/callback so switched positions.

@kevinchalet
Copy link
Member

trying out in e.g. the OpenIdDict.Sandbox.Console.Client I would see the Scopes not beeing generated while we do list them in the xml file as something that should be fixed if possible. I am not really sure for what they chould otherwhile be meant when not giving us the option to get them generated as const string or similar while registration of the Provider in the end 🤔 maybe you can tell?

We don't generate constants for scopes (some services have an insane amount of scopes so it would be a lot of work to maintain that in the long term): the scopes nodes in the XML file are exclusively used for providers that either require at least one scope to be set (Default="true") or need a specific scope to access the userinfo (Required="true").

What doesn't fit:

* `redirect_url` should be something like this: `https://localhost:44395/` + `callback/etsy`

The console app is a public client meant to be used on a desktop machine: as such, it requires using either HTTP or a custom URI scheme. If the service absolutely requires using HTTPS, use the web client app instead and usehttps://localhost:44381/callback/etsy as the redirect URI.

@DevTKSS
Copy link
Author

DevTKSS commentedNov 26, 2025
edited
Loading

@kevinchalet 🤔 I am a bit wondering now. I tryed usingOpenIddict.Sandbox.AspNetCore.Client (=> your meant Web Client ?)
and in the Startup.cs it uses

image

which does match the url I registred in the API I am calling.
so I was wondering, why this also doesnt worked (as mentioned in my last comment) and I think I might found the issue
exactly as you told, in the launchSettings.json is instead this url set:
image

but, correct me if I am wrong, shouldn't this be the same url in both places? Or does this somehow redirect this internally?

by the way, refering to your response:

The console app is a public client meant to be used on a desktop machine: as such, it requires using either HTTP or a custom URI scheme.

okay, for localhost I could change this in the registration, but generally, if https scheme is not supported in a console Client, thenwhy is this set up like this? If it is known to not work like this? I am searching for the reason that I seem to miss 😅 🤔

image

so seems like this is coming from the.SetAllowedEmbeddedWebServerPorts(49152) !
but for what exactly do we then use the Issuer Url?

And I think the response does not contain all expected contents 🤔
I am getting just one token value but should get two:
access_token andrefresh_token

┌─────────────────────────────────┬─────────────────────────────────┬────────────────────────────────┬─────────────────┐│ Claim type                      │ Claim value type                │ Claim value                    │ Claim issuer    │├─────────────────────────────────┼─────────────────────────────────┼────────────────────────────────┼─────────────────┤│ as                              │ http://www.w3.org/2001/XMLSchem │ https://www.etsy.com/          │ LOCAL AUTHORITY ││                                 │ a#string                        │                                │                 ││ oi_reg_id                       │ http://www.w3.org/2001/XMLSchem │ <realistic-token-value> │ LOCAL AUTHORITY ││                                 │ a#string                        │ aqqD8YNVg4Dws                  │                 ││ oi_prvd_name                    │ http://www.w3.org/2001/XMLSchem │ Etsy                           │ LOCAL AUTHORITY ││                                 │ a#string                        │                                │                 ││ http://schemas.microsoft.com/ac │ http://www.w3.org/2001/XMLSchem │ Etsy                           │ LOCAL AUTHORITY ││ cesscontrolservice/2010/07/clai │ a#string                        │                                │                 ││ ms/identityprovider             │                                 │                                │                 │

but expected would be anything like this as response from UserInfogetUser:

{"user_id":1,"primary_email":"user@example.com","first_name":"string","last_name":"string","image_url_75x75":"string"}

or as mentioned 2 Tokens if the output should show this.

Could you please check whats wrong?


Tryed as 2nd with theOpenIddict.Sandbox.AspNetCore.Client and while the authentication from what I am seeing should be fine in the response, its throwing an Exception for the Transportstream had been closed?

dbug: HttpsConnectionAdapter[1]      Failed to authenticate HTTPS connection.      System.IO.IOException: Fehler bei Authentifizierung, da die Gegenseite den Transportstream geschlossen hat.         bei System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)         bei System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)         bei System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)      --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---         bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()         bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)         bei Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionAdapter.<InnerOnConnectionAsync>d__10.MoveNext()

the response we are ending up here with is the code + state parameter to ourhttps://localhost:44381/callback/etsy url as configured in launchSettings.json so it should now have the correct things for the exchange...

but while the application did only ended up with the "Something went really wrong" error page, reading the console output, the auth flow was correctly looped through after this. just that the UI is getting stuck on the Error Page. seems like there is some Response redirecting to this wrong?

image

openIdDictLog-Error-Page.txt

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@kevinchaletkevinchaletkevinchalet left review comments

Assignees

@kevinchaletkevinchalet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

2 participants

@DevTKSS@kevinchalet

[8]ページ先頭

©2009-2025 Movatter.jp