[Question] Is it possible to issue tokens programmatically?
I need to generate a new token inside a custom Authenticator without passing throught the /oauth2/token endpoint, but something more like I do in custome grants with the issueToken() method.
Is there something I can use inside an autenticator to return a new JWT given an user and a client ID?
Thank you
Hi, you can see how the token is created here: \League\OAuth2\Server\Grant\PasswordGrant::respondToAccessTokenRequest, maybe this will help you
Hello Ostiwe, thank you. I already found that method and I'm using that both in Grant Flows and in Controllers.
What I don't like with this approach is that respondToAccessTokenRequest depends on ServerRequestInterface $request, while I was hoping to create the JWT programmatically without depending on the request (even because getting a Request as incoming parameter in order to create a signed JWT makes no sense to me).
Yep, it's a pity that there is no way to simply create a token, without unnecessary dependencies
I did this today, not with this bundle but with the League and League bundle for symfony but I'll drop my class here just in case it helps.
<?php
namespace App\Entity;
use DateInterval;
use DateTimeImmutable;
use League\Bundle\OAuth2ServerBundle\Entity\Scope;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
use League\OAuth2\Server\Grant\AuthCodeGrant;
class FakeToken extends AuthCodeGrant
{
public $accessTokenRepository;
public $privateKey;
private $scope;
private $authCodeTTL;
private $userIdentifer;
private ClientEntityInterface $client;
/**
* @param $accessTokenRepository
* @param $privateKey
*/
public function __construct(
ClientEntityInterface $client,
DateInterval $authCodeTTL,
$accessTokenRepository,
$privateKey,
$userIdentifer,
$scope,
) {
$this->client = $client;
$this->accessTokenRepository = $accessTokenRepository;
$this->privateKey = $privateKey;
$myScope = (new Scope());
$myScope->setIdentifier($scope);
$this->scope = $myScope;
$this->authCodeTTL = $authCodeTTL;
$this->userIdentifer = $userIdentifer;
}
public function issueMyAccessToken(
) {
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;
$accessToken = $this->accessTokenRepository->getNewToken($this->client, [$this->scope], $this->userIdentifer);
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add($this->authCodeTTL));
$accessToken->setPrivateKey($this->privateKey);
while ($maxGenerationAttempts-- > 0) {
$accessToken->setIdentifier($this->generateUniqueIdentifier());
try {
$this->accessTokenRepository->persistNewAccessToken($accessToken);
return $accessToken;
} catch (UniqueTokenIdentifierConstraintViolationException $e) {
if ($maxGenerationAttempts === 0) {
throw $e;
}
}
}
}
}
and then I call it with
$key = str_replace('%kernel.project_dir%', $kernel->getProjectDir(), $_ENV['OAUTH_PRIVATE_KEY']);
$g = (new FakeToken(
$clientRepository->getClientEntity('YOUR CLIENT ID'),
new DateInterval('P1M'),
$accessTokenRepository,
new CryptKey($key, $_ENV['OAUTH_PASSPHRASE']),
'YOUR USER IDENTIFIER',
'YOUR SCOPE',
))->issueMyAccessToken();
result was a token, which when cast to a string gives you a useable token