Remove refresh_token from OAuth2 result. Return the same access_token as a refresh_token in case when it's requested. Make access_tokens to live forever.

This commit is contained in:
ErickSkrauch
2019-12-09 19:31:54 +03:00
parent efb97a2006
commit ba7fad84a0
23 changed files with 231 additions and 297 deletions

View File

@@ -4,22 +4,40 @@ declare(strict_types=1);
namespace api\components\OAuth2\Grants;
use api\components\OAuth2\CryptTrait;
use api\components\OAuth2\Events\RequestedRefreshToken;
use api\components\OAuth2\Repositories\PublicScopeRepository;
use DateInterval;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Grant\AuthCodeGrant as BaseAuthCodeGrant;
class AuthCodeGrant extends BaseAuthCodeGrant {
use CryptTrait;
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken): ?RefreshTokenEntityInterface {
foreach ($accessToken->getScopes() as $scope) {
/**
* @param DateInterval $accessTokenTTL
* @param ClientEntityInterface $client
* @param string|null $userIdentifier
* @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes
*
* @return AccessTokenEntityInterface
* @throws \League\OAuth2\Server\Exception\OAuthServerException
* @throws \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
*/
protected function issueAccessToken(
DateInterval $accessTokenTTL,
ClientEntityInterface $client,
$userIdentifier,
array $scopes = []
): AccessTokenEntityInterface {
foreach ($scopes as $i => $scope) {
if ($scope->getIdentifier() === PublicScopeRepository::OFFLINE_ACCESS) {
return parent::issueRefreshToken($accessToken);
unset($scopes[$i]);
$this->getEmitter()->emit(new RequestedRefreshToken());
}
}
return null;
return parent::issueAccessToken($accessTokenTTL, $client, $userIdentifier, $scopes);
}
}

View File

@@ -4,7 +4,11 @@ declare(strict_types=1);
namespace api\components\OAuth2\Grants;
use api\components\OAuth2\CryptTrait;
use api\components\Tokens\TokenReader;
use Carbon\Carbon;
use common\models\OauthSession;
use InvalidArgumentException;
use Lcobucci\JWT\ValidationData;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Exception\OAuthServerException;
@@ -32,7 +36,7 @@ class RefreshTokenGrant extends BaseRefreshTokenGrant {
return $this->validateLegacyRefreshToken($refreshToken);
}
return parent::validateOldRefreshToken($request, $clientId);
return $this->validateAccessToken($refreshToken);
}
/**
@@ -84,4 +88,36 @@ class RefreshTokenGrant extends BaseRefreshTokenGrant {
];
}
/**
* @param string $jwt
* @return array
* @throws OAuthServerException
*/
private function validateAccessToken(string $jwt): array {
try {
$token = Yii::$app->tokens->parse($jwt);
} catch (InvalidArgumentException $e) {
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token', $e);
}
if (!Yii::$app->tokens->verify($token)) {
throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token');
}
if (!$token->validate(new ValidationData(Carbon::now()->getTimestamp()))) {
throw OAuthServerException::invalidRefreshToken('Token has expired');
}
$reader = new TokenReader($token);
return [
'client_id' => $reader->getClientId(),
'refresh_token_id' => '', // This value used only to invalidate old token
'access_token_id' => '', // This value used only to invalidate old token
'scopes' => $reader->getScopes(),
'user_id' => $reader->getAccountId(),
'expire_time' => null,
];
}
}