tracardi-1.0.x-dev/src/Services/Middleware/EnsureAccessTokenExistsMiddleware.php
src/Services/Middleware/EnsureAccessTokenExistsMiddleware.php
<?php
namespace Drupal\tracardi\Services\Middleware;
use Drupal\tracardi\Services\AccessToken\Context\AccessTokenContextInterface;
use Drupal\tracardi\Services\AccessToken\Storage\AccessTokenStorageInterface;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\Response;
use League\OAuth2\Client\Token\AccessToken;
use Psr\Http\Message\RequestInterface;
final class EnsureAccessTokenExistsMiddleware {
private AccessTokenStorageInterface $accessTokenStorage;
private AccessTokenContextInterface $accessTokenContext;
public function __construct(
AccessTokenStorageInterface $accessTokenStorage,
AccessTokenContextInterface $accessTokenContext
) {
$this->accessTokenStorage = $accessTokenStorage;
$this->accessTokenContext = $accessTokenContext;
}
public function __invoke(callable $handler): callable {
return function (RequestInterface $request, array $options) use ($handler) {
if ($request->hasHeader('Authorization')) {
return $handler($request, $options);
}
$token = $this->accessTokenContext->getAccessToken();
$request = $this->authenticateRequest($request, $token);
/** @var \GuzzleHttp\Promise\PromiseInterface $promise */
$promise = $handler($request, $options);
if (!$this->isUnauthorized($promise)) {
return $promise;
}
// In principle the Tracardi OAuth token has no expiry. Should we still
// get a 401, we'll fetch a new token and try again.
$accessToken = $this->fetchNewToken();
$request = $this->authenticateRequest($request, $accessToken);
return $handler($request, $options);
};
}
private function authenticateRequest(RequestInterface $request, AccessToken $accessToken): RequestInterface {
return $request->withHeader('Authorization', 'Bearer ' . $accessToken->getToken());
}
private function isUnauthorized(PromiseInterface $promise): bool {
/** @var Response $response */
$response = $promise->wait();
return $response->getStatusCode() === 401;
}
private function fetchNewToken(): AccessToken {
$this->accessTokenStorage->clear();
return $this->accessTokenContext->getAccessToken();
}
}
