Skip to content

Commit 9fd2ee0

Browse files
Merge branch 'master' into master-fix-code-challenge-error-redirect
2 parents ad924f9 + 0032301 commit 9fd2ee0

14 files changed

+185
-11
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ jobs:
4444
run: vendor/bin/phpunit --coverage-clover=coverage.clover
4545

4646
- name: Code coverage
47-
if: ${{ github.ref == 'refs/heads/master' && github.repository == 'thephpleague/oauth2-server' }}
47+
if: ${{ github.ref == 'refs/heads/master' && github.repository == 'thephpleague/oauth2-server' && startsWith(matrix.os, 'ubuntu') }}
4848
run:
4949
~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover

CHANGELOG.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
## [9.2.0] - released 2025-02-15
89
### Added
910
- Added a new function to the provided ClientTrait, `supportsGrantType` to allow the auth server to issue the response `unauthorized_client` when applicable (PR #1420)
1011

1112
### Fixed
13+
- Fix a bug on setting interval visibility of device authorization grant (PR #1410)
14+
- Fix a bug where the new poll date were not persisted when `slow_down` error happens, because the exception is thrown before calling `persistDeviceCode`. (PR #1410)
15+
- Fix a bug where `slow_down` error response may have been returned even after the user has completed the auth flow (already approved / denied the request). (PR #1410)
1216
- Clients only validated for Refresh, Device Code, and Password grants if the client is confidential (PR #1420)
17+
- Emit `RequestAccessTokenEvent` and `RequestRefreshTokenEvent` events instead of the general `RequestEvent` event when an access / refresh token is issued using device authorization grant. (PR #1467)
1318

1419
### Changed
1520
- Key permission checks ignored on Windows regardless of userland choice as cannot be run successfully on this OS (PR #1447)
@@ -22,9 +27,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2227
- In the Auth Code grant, when requesting an access token with an invalid auth code, we now respond with an invalid_grant error instead of invalid_request (PR #1433)
2328
- Fixed spec compliance issue where device access token request was mistakenly expecting to receive scopes in the request (PR #1412)
2429
- Refresh tokens pre version 9 might have had user IDs set as ints which meant they were incorrectly rejected. We now cast these values to strings to allow old refresh tokens (PR #1436)
25-
- Fixed bug on setting interval visibility of device authorization grant (PR #1410)
26-
- Fix a bug where the new poll date were not persisted when `slow_down` error happens, because the exception is thrown before calling `persistDeviceCode`. (PR #1410)
27-
- Fix a bug where `slow_down` error response may have been returned even after the user has completed the auth flow (already approved / denied the request). (PR #1410)
2830

2931
## [9.0.1] - released 2024-10-14
3032
### Fixed
@@ -675,7 +677,8 @@ Version 5 is a complete code rewrite.
675677

676678
- First major release
677679

678-
[Unreleased]: https://github.com/thephpleague/oauth2-server/compare/9.1.0...HEAD
680+
[Unreleased]: https://github.com/thephpleague/oauth2-server/compare/9.2.0...HEAD
681+
[9.2.0]: https://github.com/thephpleague/oauth2-server/compare/9.1.0...9.2.0
679682
[9.1.0]: https://github.com/thephpleague/oauth2-server/compare/9.0.1...9.1.0
680683
[9.0.1]: https://github.com/thephpleague/oauth2-server/compare/9.0.0...9.0.1
681684
[9.0.0]: https://github.com/thephpleague/oauth2-server/compare/9.0.0-RC1...9.0.0

phpstan.neon.dist

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@ parameters:
22
level: 8
33
paths:
44
- src
5-
- tests
5+
- tests
6+
ignoreErrors:
7+
-
8+
message: '#Deprecated since v5.5, please use {@see self::withValidationConstraints\(\)} instead#'
9+
reportUnmatched: false

src/Entities/ClientEntityInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function isConfidential(): bool;
4242
/*
4343
* Returns true if the client supports the given grant type.
4444
*
45-
* To be added in a future major release.
45+
* TODO: To be added in a future major release.
4646
*/
4747
// public function supportsGrantType(string $grantType): bool;
4848
}

src/Grant/DeviceCodeGrant.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException;
2626
use League\OAuth2\Server\Repositories\DeviceCodeRepositoryInterface;
2727
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
28+
use League\OAuth2\Server\RequestAccessTokenEvent;
2829
use League\OAuth2\Server\RequestEvent;
30+
use League\OAuth2\Server\RequestRefreshTokenEvent;
2931
use League\OAuth2\Server\ResponseTypes\DeviceCodeResponse;
3032
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
3133
use Psr\Http\Message\ServerRequestInterface;
@@ -166,14 +168,14 @@ public function respondToAccessTokenRequest(
166168

167169
// Issue and persist new access token
168170
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $deviceCodeEntity->getUserIdentifier(), $finalizedScopes);
169-
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
171+
$this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
170172
$responseType->setAccessToken($accessToken);
171173

172174
// Issue and persist new refresh token if given
173175
$refreshToken = $this->issueRefreshToken($accessToken);
174176

175177
if ($refreshToken !== null) {
176-
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
178+
$this->getEmitter()->emit(new RequestRefreshTokenEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request, $refreshToken));
177179
$responseType->setRefreshToken($refreshToken);
178180
}
179181

src/Grant/ImplicitGrant.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ public function completeAuthorizationRequest(AuthorizationRequestInterface $auth
172172
$finalizedScopes
173173
);
174174

175+
// TODO: next major release: this method needs `ServerRequestInterface` as an argument
176+
// $this->getEmitter()->emit(new RequestAccessTokenEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request, $accessToken));
177+
175178
$response = new RedirectResponse();
176179
$response->setRedirectUri(
177180
$this->makeRedirectUri(

src/Repositories/DeviceCodeRepositoryInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function persistDeviceCode(DeviceCodeEntityInterface $deviceCodeEntity):
3333
* Get a device code entity.
3434
*/
3535
public function getDeviceCodeEntityByDeviceCode(
36-
string $deviceCodeEntity
36+
string $deviceCodeEntity // TODO: next major release: rename to `$deviceCode`
3737
): ?DeviceCodeEntityInterface;
3838

3939
/**

tests/AuthorizationServerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public function testMultipleRequestsGetDifferentResponseTypeInstances(): void
183183
$privateKey = 'file://' . __DIR__ . '/Stubs/private.key';
184184
$encryptionKey = 'file://' . __DIR__ . '/Stubs/public.key';
185185

186-
$responseTypePrototype = new class extends BearerTokenResponse {
186+
$responseTypePrototype = new class () extends BearerTokenResponse {
187187
protected CryptKeyInterface $privateKey;
188188
protected Key|string|null $encryptionKey = null;
189189

tests/Grant/AuthCodeGrantTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
1818
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
1919
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
20+
use League\OAuth2\Server\RequestAccessTokenEvent;
21+
use League\OAuth2\Server\RequestEvent;
22+
use League\OAuth2\Server\RequestRefreshTokenEvent;
2023
use League\OAuth2\Server\RequestTypes\AuthorizationRequest;
2124
use League\OAuth2\Server\ResponseTypes\RedirectResponse;
2225
use LeagueTests\Stubs\AccessTokenEntity;
@@ -732,6 +735,27 @@ public function testRespondToAccessTokenRequest(): void
732735
$grant->setEncryptionKey($this->cryptStub->getKey());
733736
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
734737

738+
$accessTokenEventEmitted = false;
739+
$refreshTokenEventEmitted = false;
740+
741+
$grant->getListenerRegistry()->subscribeTo(
742+
RequestEvent::ACCESS_TOKEN_ISSUED,
743+
function ($event) use (&$accessTokenEventEmitted): void {
744+
self::assertInstanceOf(RequestAccessTokenEvent::class, $event);
745+
746+
$accessTokenEventEmitted = true;
747+
}
748+
);
749+
750+
$grant->getListenerRegistry()->subscribeTo(
751+
RequestEvent::REFRESH_TOKEN_ISSUED,
752+
function ($event) use (&$refreshTokenEventEmitted): void {
753+
self::assertInstanceOf(RequestRefreshTokenEvent::class, $event);
754+
755+
$refreshTokenEventEmitted = true;
756+
}
757+
);
758+
735759
$request = new ServerRequest(
736760
[],
737761
[],
@@ -763,6 +787,14 @@ public function testRespondToAccessTokenRequest(): void
763787
$response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new DateInterval('PT10M'));
764788

765789
self::assertInstanceOf(RefreshTokenEntityInterface::class, $response->getRefreshToken());
790+
791+
if (!$accessTokenEventEmitted) {
792+
self::fail('Access token issued event is not emitted.');
793+
}
794+
795+
if (!$refreshTokenEventEmitted) {
796+
self::fail('Refresh token issued event is not emitted.');
797+
}
766798
}
767799

768800
public function testRespondToAccessTokenRequestWithDefaultRedirectUri(): void

tests/Grant/ClientCredentialsGrantTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
1212
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
1313
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
14+
use League\OAuth2\Server\RequestAccessTokenEvent;
15+
use League\OAuth2\Server\RequestEvent;
1416
use LeagueTests\Stubs\AccessTokenEntity;
1517
use LeagueTests\Stubs\ClientEntity;
1618
use LeagueTests\Stubs\ScopeEntity;
@@ -53,6 +55,17 @@ public function testRespondToRequest(): void
5355
$grant->setDefaultScope(self::DEFAULT_SCOPE);
5456
$grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key'));
5557

58+
$accessTokenEventEmitted = false;
59+
60+
$grant->getListenerRegistry()->subscribeTo(
61+
RequestEvent::ACCESS_TOKEN_ISSUED,
62+
function ($event) use (&$accessTokenEventEmitted): void {
63+
self::assertInstanceOf(RequestAccessTokenEvent::class, $event);
64+
65+
$accessTokenEventEmitted = true;
66+
}
67+
);
68+
5669
$serverRequest = (new ServerRequest())->withParsedBody([
5770
'client_id' => 'foo',
5871
'client_secret' => 'bar',
@@ -64,5 +77,9 @@ public function testRespondToRequest(): void
6477
$response = $grant->respondToAccessTokenRequest($serverRequest, $responseType, new DateInterval('PT5M'));
6578

6679
self::assertNotEmpty($response->getAccessToken()->getIdentifier());
80+
81+
if (!$accessTokenEventEmitted) {
82+
self::fail('Access token issued event is not emitted.');
83+
}
6784
}
6885
}

0 commit comments

Comments
 (0)