Add encrypted Etsy app credential settings
Deploy HickLab3D Dashboard / Deploy to production (push) Successful in 23s

This commit is contained in:
Hickmeister
2026-10-10 19:08:46 +01:00
parent 89e392e5f8
commit 88dcf5101b
12 changed files with 350 additions and 8 deletions
+29 -6
View File
@@ -2,6 +2,7 @@
namespace App\Services;
use App\Models\EtsyAppCredential;
use App\Models\EtsyConnection;
use Illuminate\Support\Facades\Http;
use RuntimeException;
@@ -10,9 +11,14 @@ class Etsy
{
private const API_URL = 'https://api.etsy.com/v3';
/** @var array{keystring: ?string, shared_secret: ?string}|null */
private ?array $credentials = null;
public function configured(): bool
{
return filled(config('services.etsy.keystring')) && filled(config('services.etsy.shared_secret'));
$credentials = $this->credentials();
return filled($credentials['keystring']) && filled($credentials['shared_secret']);
}
public function authorizationUrl(string $state, string $verifier): string
@@ -24,7 +30,7 @@ class Etsy
return 'https://www.etsy.com/oauth/connect?'.http_build_query([
'response_type' => 'code', 'redirect_uri' => $this->redirectUri(),
'scope' => 'transactions_r listings_r', 'client_id' => config('services.etsy.keystring'),
'scope' => 'transactions_r listings_r', 'client_id' => $this->credentials()['keystring'],
'state' => $state, 'code_challenge' => $challenge, 'code_challenge_method' => 'S256',
], '', '&', PHP_QUERY_RFC3986);
}
@@ -33,7 +39,7 @@ class Etsy
{
$tokens = Http::asForm()->acceptJson()->connectTimeout(3)->timeout(10)
->post(self::API_URL.'/public/oauth/token', [
'grant_type' => 'authorization_code', 'client_id' => config('services.etsy.keystring'),
'grant_type' => 'authorization_code', 'client_id' => $this->credentials()['keystring'],
'redirect_uri' => $this->redirectUri(), 'code' => $code, 'code_verifier' => $verifier,
])->throw()->json();
$userId = explode('.', $tokens['access_token'] ?? '')[0];
@@ -77,7 +83,7 @@ class Etsy
}
$tokens = Http::asForm()->acceptJson()->connectTimeout(3)->timeout(10)
->post(self::API_URL.'/public/oauth/token', [
'grant_type' => 'refresh_token', 'client_id' => config('services.etsy.keystring'),
'grant_type' => 'refresh_token', 'client_id' => $this->credentials()['keystring'],
'refresh_token' => $connection->refresh_token,
])->throw()->json();
if (empty($tokens['access_token']) || empty($tokens['refresh_token'])) {
@@ -93,13 +99,30 @@ class Etsy
private function get(string $path, string $accessToken, array $query = []): array
{
return Http::withHeaders(['x-api-key' => config('services.etsy.keystring').':'.config('services.etsy.shared_secret')])
$credentials = $this->credentials();
return Http::withHeaders(['x-api-key' => $credentials['keystring'].':'.$credentials['shared_secret']])
->withToken($accessToken)->acceptJson()->connectTimeout(3)->timeout(10)
->get(self::API_URL.'/'.$path, $query)->throw()->json() ?? [];
}
private function redirectUri(): string
public function redirectUri(): string
{
return config('services.etsy.redirect_uri') ?: route('etsy.callback');
}
/** @return array{keystring: ?string, shared_secret: ?string} */
private function credentials(): array
{
if ($this->credentials !== null) {
return $this->credentials;
}
$stored = EtsyAppCredential::find(1);
return $this->credentials = [
'keystring' => $stored?->keystring ?: config('services.etsy.keystring'),
'shared_secret' => $stored?->shared_secret ?: config('services.etsy.shared_secret'),
];
}
}