Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6149d74
feat: add Etsy OAuth provider
DevTKSS Nov 3, 2025
cbfe539
docs(EtsyProvider): Add Provider usage guide with samples and specifi…
DevTKSS Nov 3, 2025
f14ca12
test: add tests for Etsy OAuth provider
DevTKSS Nov 3, 2025
7f57311
chore: Compare and align to other existing Providers
DevTKSS Nov 6, 2025
72267d1
chore: update const string to static readonly string
DevTKSS Nov 7, 2025
8492915
test(EtsyProvider): Added unit tests for EtsyAuthenticationOptions an…
DevTKSS Nov 6, 2025
0c3861b
chore: updated and documented test data in `bundle.json`
DevTKSS Nov 6, 2025
df01a95
chore: Rename Public to Personal Access Type, to match the Etsy Api n…
DevTKSS Nov 6, 2025
2b0e3ab
chore(EtsyAccessTypes): Remove commented member and test/-cases that …
DevTKSS Nov 7, 2025
1269f31
chore(EtsyProvider): tfm version bump
DevTKSS Nov 7, 2025
ee9eba0
chore: Add DetailedUserInfoClaimMappings and add xml docs
DevTKSS Nov 7, 2025
5374092
chore(Etsy): align oauth scopes with the docs table
DevTKSS Nov 7, 2025
2a791c1
chore(EtsyAuthenticationHandler): rename variables and formating appl…
DevTKSS Nov 7, 2025
e350020
chore(EtsyPostConfigureOptions): add DetailedUserInfo Config via Post…
DevTKSS Nov 7, 2025
0dc3821
chore: Update xml docs and refactor to Property pattern with declarat…
DevTKSS Nov 7, 2025
a272fde
chore(EtsyOptionsValidation): apply Review suggestions
DevTKSS Nov 7, 2025
6a3fb4c
test(EtsyProvider): Update tests accordingly to review suggestions an…
DevTKSS Nov 7, 2025
7eab685
chore: xml docs updates and update bundle.json with the placeholder v…
DevTKSS Nov 7, 2025
9a8035e
chore: implement Options fed DetailedUserInfoEndpoint and set fallbac…
DevTKSS Nov 7, 2025
293ad3a
chore: fix test builds
DevTKSS Nov 7, 2025
523e8d8
chore: set InlineData to magic string "urn:etsy:shop_id" because only…
DevTKSS Nov 8, 2025
f9358a7
chore(EtsyTests): apply workaround into PostConfigure test
DevTKSS Nov 8, 2025
b9f8c39
chore: create seperate named log methods
DevTKSS Nov 8, 2025
30c5534
docs(EtsyProvider): Add links to etsy provider docs and author, updat…
DevTKSS Nov 7, 2025
646527c
chore: applying PR rewording suggestion
DevTKSS Nov 9, 2025
967dee9
chore: Resolve Merge Conflicts from sln to slnx migration
DevTKSS Nov 27, 2025
fc30df3
refactor: Add blank line in project file, remove unused usings and up…
DevTKSS Dec 2, 2025
ffa225a
chore: include user_id in Defaults Claims
DevTKSS Dec 2, 2025
7d98335
chore: change DetailedUserInfoEndpoint to concatenated string instead…
DevTKSS Dec 2, 2025
19dfe9c
revert(EtsyPostConfigureOptions): apply DetailedUserInfo Config via P…
DevTKSS Dec 2, 2025
8a97cf3
revert(EtsyTests): apply workaround into PostConfigure test
DevTKSS Dec 2, 2025
131bc0d
chore: remove tests for validating empty or not containing shop_r Opt…
DevTKSS Dec 2, 2025
69735f1
chore: add user_id claim mapping test case
DevTKSS Dec 2, 2025
cacf36d
docs(etsy): Refactor guide and update table column headers to align w…
DevTKSS Dec 2, 2025
ca39e8f
chore: Update xml docs and introduce default value for DetailedUserIn…
DevTKSS Dec 9, 2025
fd8dda9
chore: Make DetailedUserInfo not nullable and add Ending failsafe
DevTKSS Dec 11, 2025
aee5d4a
test: remove obsolete test as DetailedUserInfoEndpoint is now not lon…
DevTKSS Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AspNet.Security.OAuth.Providers.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<File Path="docs/docusign.md" />
<File Path="docs/dropbox.md" />
<File Path="docs/ebay.md" />
<File Path="docs/etsy.md" />
<File Path="docs/eveonline.md" />
<File Path="docs/foursquare.md" />
<File Path="docs/gitcode.md" />
Expand Down Expand Up @@ -120,6 +121,7 @@
<Project Path="src/AspNet.Security.OAuth.Docusign/AspNet.Security.OAuth.Docusign.csproj" />
<Project Path="src/AspNet.Security.OAuth.Dropbox/AspNet.Security.OAuth.Dropbox.csproj" />
<Project Path="src/AspNet.Security.OAuth.Ebay/AspNet.Security.OAuth.Ebay.csproj" />
<Project Path="src/AspNet.Security.OAuth.Etsy/AspNet.Security.OAuth.Etsy.csproj" />
<Project Path="src/AspNet.Security.OAuth.EVEOnline/AspNet.Security.OAuth.EVEOnline.csproj" />
<Project Path="src/AspNet.Security.OAuth.ExactOnline/AspNet.Security.OAuth.ExactOnline.csproj" />
<Project Path="src/AspNet.Security.OAuth.Feishu/AspNet.Security.OAuth.Feishu.csproj" />
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ We would love it if you could help contributing to this repository.
* [Robert Shade](https://github.com/robert-shade)
* [saber-wang](https://github.com/saber-wang)
* [Sinan](https://github.com/SH2015)
* [Sonja Schweitzer](https://github.com/DevTKSS)
* [Stefan](https://github.com/Schlurcher)
* [Steffen Wenz](https://github.com/swenz)
* [Tathagata Chakraborty](https://github.com/tatx)
Expand Down Expand Up @@ -182,6 +183,7 @@ If a provider you're looking for does not exist, consider making a PR to add one
| Docusign | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Docusign?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Docusign/ "Download AspNet.Security.OAuth.Docusign from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Docusign?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Docusign "Download AspNet.Security.OAuth.Docusign from MyGet.org") | [Documentation](https://developers.docusign.com/platform/auth/ "Docusign developer documentation") |
| Dropbox | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Dropbox?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Dropbox/ "Download AspNet.Security.OAuth.Dropbox from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Dropbox?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Dropbox "Download AspNet.Security.OAuth.Dropbox from MyGet.org") | [Documentation](https://www.dropbox.com/developers/reference/oauth-guide?_tk=guides_lp&_ad=deepdive2&_camp=oauth "Dropbox developer documentation") |
| eBay | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Ebay?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Ebay/ "Download AspNet.Security.OAuth.Ebay from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Ebay?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Ebay "Download AspNet.Security.OAuth.Ebay from MyGet.org") | [Documentation](https://developer.ebay.com/api-docs/static/oauth-tokens.html "eBay developer documentation") |
| Etsy | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Etsy?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Etsy/ "Download AspNet.Security.OAuth.Etsy from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Etsy?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Etsy "Download AspNet.Security.OAuth.Etsy from MyGet.org") | [Documentation](https://developers.etsy.com/documentation/essentials/authentication "Etsy developer documentation") |
| EVEOnline | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.EVEOnline?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.EVEOnline/ "Download AspNet.Security.OAuth.EVEOnline from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.EVEOnline?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.EVEOnline "Download AspNet.Security.OAuth.EVEOnline from MyGet.org") | [Documentation](https://github.com/esi/esi-docs/blob/master/docs/sso/web_based_sso_flow.md "EVEOnline developer documentation") |
| ExactOnline | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.ExactOnline?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.ExactOnline/ "Download AspNet.Security.OAuth.ExactOnline from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.ExactOnline?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.ExactOnline "Download AspNet.Security.OAuth.ExactOnline from MyGet.org") | [Documentation](https://support.exactonline.com/community/s/knowledge-base#All-All-DNO-Content-gettingstarted "ExactOnline developer documentation") |
| Feishu | [![NuGet](https://img.shields.io/nuget/v/AspNet.Security.OAuth.Feishu?logo=nuget&label=NuGet&color=blue)](https://www.nuget.org/packages/AspNet.Security.OAuth.Feishu/ "Download AspNet.Security.OAuth.Feishu from NuGet.org") | [![MyGet](https://img.shields.io/myget/aspnet-contrib/vpre/AspNet.Security.OAuth.Feishu?logo=nuget&label=MyGet&color=blue)](https://www.myget.org/feed/aspnet-contrib/package/nuget/AspNet.Security.OAuth.Feishu "Download AspNet.Security.OAuth.Feishu from MyGet.org") | [Documentation](https://open.feishu.cn/document/common-capabilities/sso/web-application-sso/web-app-overview "Feishu developer documentation") |
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ covered by the section above.
| Discord | _Optional_ | [Documentation](discord.md "Discord provider documentation") |
| Docusign | **Required** | [Documentation](docusign.md "Docusign provider documentation") |
| eBay | **Required** | [Documentation](ebay.md "eBay provider documentation") |
| Etsy | _Optional_ | [Documentation](etsy.md "Etsy provider documentation") |
| EVEOnline | _Optional_ | [Documentation](eveonline.md "EVEOnline provider documentation") |
| Foursquare | _Optional_ | [Documentation](foursquare.md "Foursquare provider documentation") |
| GitCode | _Optional_ | [Documentation](gitcode.md "GitCode provider documentation") |
Expand Down
55 changes: 55 additions & 0 deletions docs/etsy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Integrating the Etsy Provider

Etsy's OAuth implementation uses Authorization Code with **PKCE** and issues **refresh tokens**.

This provider enables PKCE by default and validates scopes to match Etsy's requirements.

- [Integrating the Etsy Provider](#integrating-the-etsy-provider)
- [Example](#example)
- [Required Additional Settings](#required-additional-settings)
- [Optional Settings](#optional-settings)
- [Quick Links](#quick-links)

## Example

```csharp
using AspNet.Security.OAuth.Etsy;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

var builder = WebApplication.CreateBuilder(args);

builder.Services
.AddAuthentication(options => { /* Authentication options */ })
.AddEtsy(options =>
{
options.ClientId = "my-etsy-client-id";
options.ClientSecret = "my-etsy-client-secret"; // Optional as Etsy requires PKCE
options.IncludeDetailedUserInfo = true; // Optional to get first name, last name, email claims
options.ClaimActions.MapImageClaim(); // Optional Extension to map the image_url_75x75 claim, will not be mapped automatically
});
```

## Required Additional Settings

- You can obtain the Client ID (`keystring`) for your app by registering your application on [Etsy's developer portal](https://www.etsy.com/developers/your-apps).
- The ClientSecret (`shared secret` in the Etsy app details) is optional for public clients using PKCE.

## Optional Settings

| Property Name | Property Type | Description | Default Value |
|:--|:--|:--|:--|
| `IncludeDetailedUserInfo` | `bool` | Fetch extended profile data with auto-mapped claims (Email, GivenName, Surname). | `false` |
| `ClaimActions.MapImageClaim()` | Extension method | Map the `image_url_75x75` claim to `EtsyAuthenticationConstants.Claims.ImageUrl`. | Not mapped automatically |
| `DetailedUserInfoEndpoint` | `string` | Endpoint to retrieve detailed user information. | `https://openapi.etsy.com/v3/application/users/` |

Additional helpers are available via `EtsyAuthenticationConstants.Scopes.*` for Etsy OAuth scopes and `EtsyAuthenticationConstants.Claims.*` for claim type constants used for the `getMe` and `getUser` endpoints.

## Quick Links

| Resource | Link |
|:--|:--|
| Register your App on Etsy: | [Apps You've Made](https://www.etsy.com/developers/your-apps) |
| Official Etsy Authentication API Documentation: | [Etsy Developer Documentation](https://developers.etsy.com/documentation/essentials/authentication) |
| Requesting a Refresh OAuth Token: | [Etsy Refresh Token Guide](https://developers.etsy.com/documentation/essentials/authentication#requesting-a-refresh-oauth-token) |
| Etsy API Reference: | [Etsy API Reference](https://developers.etsy.com/documentation/reference) |
21 changes: 21 additions & 0 deletions src/AspNet.Security.OAuth.Etsy/AspNet.Security.OAuth.Etsy.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageValidationBaselineVersion>10.1.0</PackageValidationBaselineVersion>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<!-- TODO Remove once published to NuGet.org -->
<DisablePackageBaselineValidation>true</DisablePackageBaselineValidation>
</PropertyGroup>

<PropertyGroup>
<Description>ASP.NET Core security middleware enabling Etsy authentication.</Description>
<Authors>Sonja Schweitzer</Authors>
<PackageTags>aspnetcore;authentication;etsy;oauth;security</PackageTags>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="All" />
</ItemGroup>

</Project>
24 changes: 24 additions & 0 deletions src/AspNet.Security.OAuth.Etsy/ClaimActionCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

using AspNet.Security.OAuth.Etsy;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Provides extension methods for <see cref="ClaimActionCollection"/> to map Etsy API specific user claims.
/// </summary>
public static class ClaimActionCollectionExtensions
{
/// <summary>
/// Maps the Etsy user's profile image URL (75x75) to the <see cref="EtsyAuthenticationConstants.Claims.ImageUrl"/> claim.
/// </summary>
public static void MapImageClaim(this ClaimActionCollection collection)
{
collection.MapJsonKey(EtsyAuthenticationConstants.Claims.ImageUrl, "image_url_75x75");
}
}
94 changes: 94 additions & 0 deletions src/AspNet.Security.OAuth.Etsy/EtsyAuthenticationConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

namespace AspNet.Security.OAuth.Etsy;

/// <summary>
/// Contains constants specific to the <see cref="EtsyAuthenticationHandler"/>.
/// </summary>
public static class EtsyAuthenticationConstants
{
/// <summary>
/// Contains claim type constants specific to Etsy authentication.
/// </summary>
public static class Claims
{
/// <summary>The claim type for the user's Etsy user ID.</summary>
public static readonly string UserId = "urn:etsy:user_id";

/// <summary>The claim type for the user's Etsy shop ID.</summary>
public static readonly string ShopId = "urn:etsy:shop_id";

/// <summary>The claim type for the user's profile image URL.</summary>
public static readonly string ImageUrl = "urn:etsy:image_url";
}

/// <summary>
/// Contains <see href="https://developers.etsy.com/documentation/reference#section/Authentication/oauth2">Etsy OAuth Scopes</see> constants for Etsy authentication.
/// </summary>
public static class Scopes
{
/// <summary>See billing and shipping addresses</summary>
public static readonly string AddressRead = "address_r";

/// <summary>Update billing and shipping addresses</summary>
public static readonly string AddressWrite = "address_w";

/// <summary>See all billing statement data</summary>
public static readonly string BillingRead = "billing_r";

/// <summary>Read shopping carts</summary>
public static readonly string CartRead = "cart_r";

/// <summary>Add/Remove from shopping carts</summary>
public static readonly string CartWrite = "cart_w";

/// <summary>Read a user profile</summary>
public static readonly string EmailRead = "email_r";

/// <summary>See private favorites</summary>
public static readonly string FavoritesRead = "favorites_r";

/// <summary>Add/Remove favorites</summary>
public static readonly string FavoritesWrite = "favorites_w";

/// <summary>See purchase info in feedback</summary>
public static readonly string FeedbackRead = "feedback_r";

/// <summary>Delete listings</summary>
public static readonly string ListingsDelete = "listings_d";

/// <summary>See all listings (including expired etc)</summary>
public static readonly string ListingsRead = "listings_r";

/// <summary>Create/Edit listings</summary>
public static readonly string ListingsWrite = "listings_w";

/// <summary>See all profile data</summary>
public static readonly string ProfileRead = "profile_r";

/// <summary>Update user profile, avatar, etc</summary>
public static readonly string ProfileWrite = "profile_w";

/// <summary>See recommended listings</summary>
public static readonly string RecommendRead = "recommend_r";

/// <summary>Accept/Reject recommended listings</summary>
public static readonly string RecommendWrite = "recommend_w";

/// <summary>See private shop info</summary>
public static readonly string ShopsRead = "shops_r";

/// <summary>Update shop</summary>
public static readonly string ShopsWrite = "shops_w";

/// <summary>See all checkout/payment data</summary>
public static readonly string TransactionsRead = "transactions_r";

/// <summary>Update receipts</summary>
public static readonly string TransactionsWrite = "transactions_w";
}
}
53 changes: 53 additions & 0 deletions src/AspNet.Security.OAuth.Etsy/EtsyAuthenticationDefaults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
* for more information concerning the license and the contributors participating to this project.
*/

namespace AspNet.Security.OAuth.Etsy;

/// <summary>
/// Default values used by the Etsy authentication middleware.
/// </summary>
public static class EtsyAuthenticationDefaults
{
/// <summary>
/// Default value for <see cref="AuthenticationScheme.Name"/>.
/// </summary>
public const string AuthenticationScheme = "Etsy";

/// <summary>
/// Default value for <see cref="AuthenticationScheme.DisplayName"/>.
/// </summary>
public static readonly string DisplayName = "Etsy";

/// <summary>
/// Default value for <see cref="AuthenticationSchemeOptions.ClaimsIssuer"/>.
/// </summary>
public static readonly string Issuer = "Etsy";

/// <summary>
/// Default value for <see cref="RemoteAuthenticationOptions.CallbackPath"/>.
/// </summary>
public static readonly string CallbackPath = "/signin-etsy";

/// <summary>
/// Default value for <see cref="OAuthOptions.AuthorizationEndpoint"/>.
/// </summary>
public static readonly string AuthorizationEndpoint = "https://www.etsy.com/oauth/connect";

/// <summary>
/// Default value for <see cref="OAuthOptions.TokenEndpoint"/>.
/// </summary>
public static readonly string TokenEndpoint = "https://openapi.etsy.com/v3/public/oauth/token";

/// <summary>
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/> <see href="https://developers.etsy.com/documentation/reference/#operation/getMe">Etsy getMe Endpoint</see>.
/// </summary>
public static readonly string UserInformationEndpoint = "https://openapi.etsy.com/v3/application/users/me";

/// <summary>
/// Default value for receiving the user profile based upon a unique user ID <see href="https://developers.etsy.com/documentation/reference/#operation/getUser">getUser</see>.
/// </summary>
public static readonly string DetailedUserInfoEndpoint = "https://openapi.etsy.com/v3/application/users/";
}
Loading