Skip to content
This repository was archived by the owner on Mar 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
687f558
Basic implementation of private claims
skroczek Jun 3, 2020
1ceece8
Adds private claims to the grant types
skroczek Jun 4, 2020
c154242
Fixes styles
skroczek Jun 4, 2020
5f99b85
Makes ClaimRepository optional in AuthorizationServer constructor.
skroczek Jun 4, 2020
91544c2
Fixes styles II
skroczek Jun 4, 2020
3f75c45
Adds testing for claims
skroczek Jun 5, 2020
c51fcf4
Fixes style of claim entity stub
skroczek Jun 5, 2020
6a23b5d
Fixes phpstan errors
skroczek Jun 5, 2020
a857813
Removes unused JsonSerializable interface
skroczek Jul 16, 2020
98b8c0a
Adds ClaimEntityTrait
skroczek Jul 16, 2020
2d4e048
Removes useless claim parameter
skroczek Jul 16, 2020
96176d8
Removes confusing ClaimEntity argument
skroczek Jul 16, 2020
13bb765
Asserts that the claim has been set
skroczek Jul 16, 2020
c1db633
Fixes cs
skroczek Jul 16, 2020
c750c3c
Fixes phpstan error
skroczek Jul 16, 2020
0fff30d
Adds and uses TokenInterface::addClaim() method and removes $claims p…
skroczek Jul 23, 2020
20d8d98
Add blank line above block
Sephster Jul 27, 2020
7043485
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
12bcdf5
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
7a8bc57
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
31a4bd0
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
49534e8
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
f1fda93
Fix formatting and make if check more explicit
Sephster Jul 27, 2020
a350bb4
Changes copyright
skroczek Jul 27, 2020
245aa4f
StyleCI fix
Sephster Sep 30, 2020
3eb7ec1
Remove getClaims and addClaim from TokenInterface
Sephster Oct 1, 2020
ecc63c6
Add method exists for addClaim on token
Sephster Oct 1, 2020
7947a61
StyleCI fixes
Sephster Oct 1, 2020
c7e4b60
Various fixups post rebase
reedy Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/.styleci.yml export-ignore
/phpstan.neon export-ignore
/phpunit.xml.dist export-ignore
/roave-bc-check.yaml export-ignore
/CHANGELOG.md export-ignore
/CONTRIBUTING.md export-ignore
/README.md export-ignore
Expand Down
12 changes: 10 additions & 2 deletions examples/src/Repositories/AccessTokenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,20 @@ public function isAccessTokenRevoked($tokenId): bool
/**
* {@inheritdoc}
*/
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null): AccessTokenEntityInterface
{
public function getNewToken(
ClientEntityInterface $clientEntity,
array $scopes,
string|null $userIdentifier = null,
array $claims = []
): AccessTokenEntityInterface {
$accessToken = new AccessTokenEntity();

$accessToken->setClient($clientEntity);

foreach ($claims as $claim) {
$accessToken->addClaim($claim);
}

foreach ($scopes as $scope) {
$accessToken->addScope($scope);
}
Expand Down
3 changes: 3 additions & 0 deletions roave-bc-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parameters:
ignoreErrors:
- '#\[BC\] ADDED: Method setClaimRepository\(\) was added to interface #'
5 changes: 4 additions & 1 deletion src/AuthorizationServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use League\OAuth2\Server\Exception\OAuthServerException;
use League\OAuth2\Server\Grant\GrantTypeInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\RequestTypes\AuthorizationRequestInterface;
Expand Down Expand Up @@ -66,7 +67,8 @@ public function __construct(
CryptKeyInterface|string $privateKey,
#[SensitiveParameter]
Key|string $encryptionKey,
ResponseTypeInterface|null $responseType = null
ResponseTypeInterface|null $responseType = null,
private ClaimRepositoryInterface|null $claimRepository = null
) {
if ($privateKey instanceof CryptKeyInterface === false) {
$privateKey = new CryptKey($privateKey);
Expand Down Expand Up @@ -96,6 +98,7 @@ public function enableGrantType(GrantTypeInterface $grantType, DateInterval|null
$grantType->setAccessTokenRepository($this->accessTokenRepository);
$grantType->setClientRepository($this->clientRepository);
$grantType->setScopeRepository($this->scopeRepository);
$grantType->setClaimRepository($this->claimRepository);
$grantType->setDefaultScope($this->defaultScope);
$grantType->setPrivateKey($this->privateKey);
$grantType->setEmitter($this->getEmitter());
Expand Down
26 changes: 26 additions & 0 deletions src/Entities/ClaimEntityInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

/**
* @author Sebastian Kroczek <me@xbug.de>
* @copyright Copyright (c) Alex Bilbie
* @license http://mit-license.org/
*
* @link https://github.com/thephpleague/oauth2-server
*/

declare(strict_types=1);

namespace League\OAuth2\Server\Entities;

interface ClaimEntityInterface
{
/**
* Get the claim's name.
*/
public function getName(): string;

/**
* Get the claim's value
*/
public function getValue(): mixed;
}
20 changes: 17 additions & 3 deletions src/Entities/Traits/AccessTokenTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Token;
use League\OAuth2\Server\CryptKeyInterface;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use RuntimeException;
Expand Down Expand Up @@ -64,13 +65,21 @@ private function convertToJWT(): Token
{
$this->initJwtConfiguration();

return $this->jwtConfiguration->builder()
->permittedFor($this->getClient()->getIdentifier())
$builder = $this->jwtConfiguration->builder();
$builder->permittedFor($this->getClient()->getIdentifier())
->identifiedBy($this->getIdentifier())
->issuedAt(new DateTimeImmutable())
->canOnlyBeUsedAfter(new DateTimeImmutable())
->expiresAt($this->getExpiryDateTime())
->relatedTo($this->getSubjectIdentifier())
->relatedTo($this->getSubjectIdentifier());

foreach ($this->getClaims() as $claim) {
/* @phpstan-ignore-next-line */
$builder->withClaim($claim->getName(), $claim->getValue());
}

return $builder
// Set scope claim late to prevent it from being overridden.
->withClaim('scopes', $this->getScopes())
->getToken($this->jwtConfiguration->signer(), $this->jwtConfiguration->signingKey());
}
Expand All @@ -97,6 +106,11 @@ abstract public function getUserIdentifier(): string|null;
*/
abstract public function getScopes(): array;

/**
* @return ClaimEntityInterface[]
*/
abstract public function getClaims(): array;

/**
* @return non-empty-string
*/
Expand Down
36 changes: 36 additions & 0 deletions src/Entities/Traits/ClaimEntityTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/**
* @author Sebastian Kroczek <me@xbug.de>
* @copyright Copyright (c) Alex Bilbie
* @license http://mit-license.org/
*
* @link https://github.com/thephpleague/oauth2-server
*/

declare(strict_types=1);

namespace League\OAuth2\Server\Entities\Traits;

trait ClaimEntityTrait
{
protected string $name;

protected mixed $value;

/**
* Returns the name of the claim
*/
public function getName(): string
{
return $this->name;
}

/**
* Returns the claims value
*/
public function getValue(): mixed
{
return $this->value;
}
}
24 changes: 24 additions & 0 deletions src/Entities/Traits/TokenEntityTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace League\OAuth2\Server\Entities\Traits;

use DateTimeImmutable;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;

Expand All @@ -27,6 +28,11 @@ trait TokenEntityTrait

protected DateTimeImmutable $expiryDateTime;

/**
* @var ClaimEntityInterface[]
*/
protected array $claims = [];

/**
* @var non-empty-string|null
*/
Expand All @@ -52,6 +58,24 @@ public function getScopes(): array
return array_values($this->scopes);
}

/**
* Associate a claim with the token.
*/
public function addClaim(ClaimEntityInterface $claim): void
{
$this->claims[] = $claim;
}

/**
* Return an array of claims associated with the token.
*
* @return ClaimEntityInterface[]
*/
public function getClaims(): array
{
return $this->claims;
}

/**
* Get the token's expiry date time.
*/
Expand Down
20 changes: 19 additions & 1 deletion src/Grant/AbstractGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use League\OAuth2\Server\CryptTrait;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Entities\ClaimEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
Expand All @@ -32,6 +33,7 @@
use League\OAuth2\Server\RedirectUriValidators\RedirectUriValidator;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
Expand All @@ -50,6 +52,7 @@
use function bin2hex;
use function explode;
use function is_string;
use function method_exists;
use function random_bytes;
use function substr;
use function trim;
Expand All @@ -74,6 +77,8 @@ abstract class AbstractGrant implements GrantTypeInterface

protected AuthCodeRepositoryInterface $authCodeRepository;

protected ?ClaimRepositoryInterface $claimRepository;

protected RefreshTokenRepositoryInterface $refreshTokenRepository;

protected UserRepositoryInterface $userRepository;
Expand Down Expand Up @@ -106,6 +111,11 @@ public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refre
$this->refreshTokenRepository = $refreshTokenRepository;
}

public function setClaimRepository(?ClaimRepositoryInterface $claimRepository): void
{
$this->claimRepository = $claimRepository;
}

public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository): void
{
$this->authCodeRepository = $authCodeRepository;
Expand Down Expand Up @@ -410,6 +420,7 @@ protected function getServerParameter(string $parameter, ServerRequestInterface
* Issue an access token.
*
* @param ScopeEntityInterface[] $scopes
* @param ClaimEntityInterface[] $claims
*
* @throws OAuthServerException
* @throws UniqueTokenIdentifierConstraintViolationException
Expand All @@ -418,14 +429,21 @@ protected function issueAccessToken(
DateInterval $accessTokenTTL,
ClientEntityInterface $client,
string|null $userIdentifier,
array $scopes = []
array $scopes = [],
array $claims = []
): AccessTokenEntityInterface {
$maxGenerationAttempts = self::MAX_RANDOM_TOKEN_GENERATION_ATTEMPTS;

$accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier);
$accessToken->setExpiryDateTime((new DateTimeImmutable())->add($accessTokenTTL));
$accessToken->setPrivateKey($this->privateKey);

if (method_exists($accessToken, 'addClaim')) {
foreach ($claims as $claim) {
$accessToken->addClaim($claim);
}
}

while ($maxGenerationAttempts-- > 0) {
$accessToken->setIdentifier($this->generateUniqueIdentifier());
try {
Expand Down
12 changes: 11 additions & 1 deletion src/Grant/AuthCodeGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,18 @@ public function respondToAccessTokenRequest(
$this->validateCodeChallenge($authCodePayload, $codeVerifier);
}

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims(
$this->getIdentifier(),
$client,
$authCodePayload->user_id
);
}

// Issue and persist new access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes, $privateClaims);
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
$responseType->setAccessToken($accessToken);

Expand Down
8 changes: 7 additions & 1 deletion src/Grant/ClientCredentialsGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@ public function respondToAccessTokenRequest(
// Finalize the requested scopes
$finalizedScopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims($this->getIdentifier(), $client);
}

// Issue and persist access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes);
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes, $privateClaims);

// Send event to emitter
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
Expand Down
6 changes: 6 additions & 0 deletions src/Grant/GrantTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use League\OAuth2\Server\CryptKeyInterface;
use League\OAuth2\Server\EventEmitting\EmitterAwareInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use League\OAuth2\Server\Repositories\ClaimRepositoryInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
use League\OAuth2\Server\RequestTypes\AuthorizationRequestInterface;
Expand Down Expand Up @@ -115,6 +116,11 @@ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessT
*/
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository): void;

/**
* Set the claim repository.
*/
public function setClaimRepository(?ClaimRepositoryInterface $claimRepository): void;

/**
* Set the default scope.
*/
Expand Down
13 changes: 12 additions & 1 deletion src/Grant/ImplicitGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,22 @@ public function completeAuthorizationRequest(AuthorizationRequestInterface $auth
$authorizationRequest->getUser()->getIdentifier()
);

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims(
$this->getIdentifier(),
$authorizationRequest->getClient(),
$authorizationRequest->getUser()->getIdentifier()
);
}

$accessToken = $this->issueAccessToken(
$this->accessTokenTTL,
$authorizationRequest->getClient(),
$authorizationRequest->getUser()->getIdentifier(),
$finalizedScopes
$finalizedScopes,
$privateClaims
);

// TODO: next major release: this method needs `ServerRequestInterface` as an argument
Expand Down
14 changes: 13 additions & 1 deletion src/Grant/PasswordGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,20 @@ public function respondToAccessTokenRequest(
$user->getIdentifier()
);

$privateClaims = [];

if ($this->claimRepository !== null) {
$privateClaims = $this->claimRepository->getClaims($this->getIdentifier(), $client, $user->getIdentifier());
}

// Issue and persist new access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
$accessToken = $this->issueAccessToken(
$accessTokenTTL,
$client,
$user->getIdentifier(),
$finalizedScopes,
$privateClaims
);
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
$responseType->setAccessToken($accessToken);

Expand Down
Loading