diff --git a/.config/.env_example b/.config/.env_example index 5ab2ebb..cee8a6d 100644 --- a/.config/.env_example +++ b/.config/.env_example @@ -56,6 +56,12 @@ DISCORD_SECRET= DISCORD_CALLBACK_URL= #DISCORD_TESTUSER= +# https://www.etsy.com/developers/register +ETSY_KEY= +ETSY_SECRET= +ETSY_CALLBACK_URL= +#ETSY_TESTUSER= + # https://www.flickr.com/services/apps/create/ FLICKR_KEY= FLICKR_SECRET= diff --git a/examples/get-token/Etsy.php b/examples/get-token/Etsy.php new file mode 100644 index 0000000..e1a9c9d --- /dev/null +++ b/examples/get-token/Etsy.php @@ -0,0 +1,21 @@ + + * @copyright 2024 smiley + * @license MIT + */ +declare(strict_types=1); + +use chillerlan\OAuth\Providers\Etsy; + +require_once __DIR__.'/../provider-example-common.php'; + +/** @var \OAuthExampleProviderFactory $factory */ +$provider = $factory->getProvider(Etsy::class); + +require_once __DIR__.'/_flow-oauth2.php'; + +exit; diff --git a/src/Providers/Etsy.php b/src/Providers/Etsy.php new file mode 100644 index 0000000..48b4bf0 --- /dev/null +++ b/src/Providers/Etsy.php @@ -0,0 +1,84 @@ + + * @copyright 2024 smiley + * @license MIT + * + * @noinspection PhpUnused + */ +declare(strict_types=1); + +namespace chillerlan\OAuth\Providers; + +use chillerlan\OAuth\Core\{CSRFToken, OAuth2Provider, PKCE, TokenRefresh}; + +/** + * @see https://developers.etsy.com/documentation/essentials/authentication + */ +class Etsy extends OAuth2Provider implements CSRFToken, PKCE, TokenRefresh{ + + public const IDENTIFIER = 'ETSY'; + + public const SCOPE_ADDRESS_R = 'address_r'; + public const SCOPE_ADDRESS_W = 'address_w'; + public const SCOPE_BILLING_R = 'billing_r'; + public const SCOPE_CART_R = 'cart_r'; + public const SCOPE_CART_W = 'cart_w'; + public const SCOPE_EMAIL_R = 'email_r'; + public const SCOPE_FAVORITES_R = 'favorites_r'; + public const SCOPE_FAVORITES_W = 'favorites_w'; + public const SCOPE_FEEDBACK_R = 'feedback_r'; + public const SCOPE_LISTINGS_D = 'listings_d'; + public const SCOPE_LISTINGS_R = 'listings_r'; + public const SCOPE_LISTINGS_W = 'listings_w'; + public const SCOPE_PROFILE_R = 'profile_r'; + public const SCOPE_PROFILE_W = 'profile_w'; + public const SCOPE_RECOMMEND_R = 'recommend_r'; + public const SCOPE_RECOMMEND_W = 'recommend_w'; + public const SCOPE_SHOPS_R = 'shops_r'; + public const SCOPE_SHOPS_W = 'shops_w'; + public const SCOPE_TRANSACTIONS_R = 'transactions_r'; + public const SCOPE_TRANSACTIONS_W = 'transactions_w'; + + public const DEFAULT_SCOPES = [ + self::SCOPE_EMAIL_R, + ]; + + protected string $authorizationURL = 'https://www.etsy.com/oauth/connect'; + protected string $accessTokenURL = 'https://api.etsy.com/v3/public/oauth/token'; + protected string $apiURL = 'https://api.etsy.com'; + protected string|null $apiDocs = 'https://developers.etsy.com/documentation/reference/'; + protected string|null $applicationURL = 'https://www.etsy.com/developers/your-apps'; + protected string|null $userRevokeURL = 'hhttps://www.etsy.com/your/apps'; + + /** + * @inheritDoc + */ + protected function getAccessTokenRequestBodyParams(string $code):array{ + + $params = [ + 'code' => $code, + 'grant_type' => 'authorization_code', + 'redirect_uri' => $this->options->callbackURL, + 'client_id' => $this->options->key, + ]; + + return $this->setCodeVerifier($params); + } + + /** + * @inheritDoc + */ + protected function getRefreshAccessTokenRequestBodyParams(string $refreshToken):array{ + return [ + 'client_id' => $this->options->key, + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken, + ]; + } + + +} diff --git a/tests/Providers/Unit/EtsyTest.php b/tests/Providers/Unit/EtsyTest.php new file mode 100644 index 0000000..a522ac7 --- /dev/null +++ b/tests/Providers/Unit/EtsyTest.php @@ -0,0 +1,50 @@ + + * @copyright 2024 smiley + * @license MIT + */ +declare(strict_types=1); + +namespace chillerlan\OAuthTest\Providers\Unit; + +use chillerlan\OAuth\Core\TokenRefresh; +use chillerlan\OAuth\Providers\Etsy; + +/** + * + */ +class EtsyTest extends OAuth2ProviderUnitTestAbstract{ + + protected function getProviderFQCN():string{ + return Etsy::class; + } + + public function testGetAccessTokenRequestBodyParams():void{ + $verifier = $this->provider->generateVerifier($this->options->pkceVerifierLength); + + $this->storage->storeCodeVerifier($verifier, $this->provider->name); + + $params = $this->invokeReflectionMethod('getAccessTokenRequestBodyParams', ['*test_code*']); + + $this::assertSame('*test_code*', $params['code']); + $this::assertSame($this->options->callbackURL, $params['redirect_uri']); + $this::assertSame('authorization_code', $params['grant_type']); + + $this::assertSame($this->options->key, $params['client_id']); + + $this::assertSame($verifier, $params['code_verifier']); + } + + public function testGetRefreshAccessTokenRequestBodyParams():void{ + $params = $this->invokeReflectionMethod('getRefreshAccessTokenRequestBodyParams', ['*refresh_token*']); + + $this::assertSame('*refresh_token*', $params['refresh_token']); + $this::assertSame($this->options->key, $params['client_id']); + $this::assertSame('refresh_token', $params['grant_type']); + } + +}