Files
id/src/Id/Repository/AppTokenRepository.php
T
Maurice PreußandClaude Opus 5.5 8de737641e App subscriptions: manage a user's subscriptions with the app's own token
- $user->appSubscriptions(): create (idempotency_key), find, all, checkout, revoke, pause,
  resume, update against /v1/client/subscriptions with a client credentials token, so apps don't
  depend on the user's login
- user id from the billable's anikeen_id (AnikeenId::useUserIdField())
- ApiException with status, stable error code, isNotFound/isConflict/isTemporary; network
  errors no longer escape as raw Guzzle exceptions
- rejected app tokens are renewed once; asApp() never changes the shared client's token
- tests (testbench + Guzzle mock) and CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:02:16 +01:00

65 lines
1.5 KiB
PHP

<?php
namespace Anikeen\Id\Repository;
use Anikeen\Id\AnikeenId;
use Anikeen\Id\Contracts\AppTokenRepository as Repository;
use Anikeen\Id\Exceptions\RequestFreshAccessTokenException;
use Illuminate\Support\Facades\Cache;
class AppTokenRepository implements Repository
{
public const ACCESS_TOKEN_CACHE_KEY = 'anikeen-id:access_token';
private AnikeenId $client;
public function __construct()
{
$this->client = app(AnikeenId::class);
}
/**
* {@inheritDoc}
*/
public function getAccessToken(): string
{
$accessToken = Cache::get(self::ACCESS_TOKEN_CACHE_KEY);
if ($accessToken) {
return $accessToken;
}
return $this->requestFreshAccessToken('*');
}
/**
* Drop the cached token, e.g. after the ID service rejected it.
*/
public function forgetAccessToken(): void
{
Cache::forget(self::ACCESS_TOKEN_CACHE_KEY);
}
/**
* @throws RequestFreshAccessTokenException
*/
private function requestFreshAccessToken(string $scope): mixed
{
$result = $this->getClient()->retrievingToken('client_credentials', [
'scope' => $scope,
]);
if (!$result->success()) {
throw RequestFreshAccessTokenException::fromResponse($result->response());
}
Cache::put(self::ACCESS_TOKEN_CACHE_KEY, $accessToken = $result->data()->access_token, now()->addWeek());
return $accessToken;
}
private function getClient(): AnikeenId
{
return $this->client;
}
}