Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[13.x] Support OAuth2 Server v9 #1734

Merged
merged 22 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 1 addition & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ jobs:
strategy:
fail-fast: true
matrix:
php: ['8.0', 8.1, 8.2, 8.3]
php: [8.1, 8.2, 8.3]
laravel: [9, 10, 11]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a next PR we may drop Laravel v9 and v10 support as well as PHP 8.1

exclude:
- php: '8.0'
laravel: 10
- php: '8.0'
laravel: 11
- php: 8.1
laravel: 11
- php: 8.3
Expand Down
16 changes: 16 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

## General Notes

## Upgrading To 13.0 From 12.x

### Minimum PHP Version

PR: https://github.com/laravel/passport/pull/1734

PHP 8.1 is now the minimum required version.

### OAuth2 Server

PR: https://github.com/laravel/passport/pull/1734

The `league/oauth2-server` Composer package which is utilized internally by Passport has been updated to 9.0, which adds additional types to method signatures. To ensure your application is compatible, you should review this package's complete [changelog](https://github.com/thephpleague/oauth2-server/blob/master/CHANGELOG.md#900---released-2024-05-13).

## Upgrading To 12.0 From 11.x

### Migration Changes
Expand All @@ -14,6 +28,8 @@ php artisan vendor:publish --tag=passport-migrations

### Password Grant Type

PR: https://github.com/laravel/passport/pull/1715

The password grant type is disabled by default. You may enable it by calling the `enablePasswordGrant` method in the `boot` method of your application's `App\Providers\AppServiceProvider` class:

```php
Expand Down
15 changes: 8 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
}
],
"require": {
"php": "^8.0",
"php": "^8.1",
"ext-json": "*",
"ext-openssl": "*",
"firebase/php-jwt": "^6.4",
"illuminate/auth": "^9.21|^10.0|^11.0",
"illuminate/console": "^9.21|^10.0|^11.0",
Expand All @@ -26,18 +27,18 @@
"illuminate/encryption": "^9.21|^10.0|^11.0",
"illuminate/http": "^9.21|^10.0|^11.0",
"illuminate/support": "^9.21|^10.0|^11.0",
"lcobucci/jwt": "^4.3|^5.0",
"league/oauth2-server": "^8.5.3",
"lcobucci/jwt": "^5.0",
"league/oauth2-server": "^9.0",
"nyholm/psr7": "^1.5",
"phpseclib/phpseclib": "^2.0|^3.0",
"phpseclib/phpseclib": "^3.0",
"symfony/console": "^6.0|^7.0",
"symfony/psr-http-message-bridge": "^2.1|^6.0|^7.0"
"symfony/psr-http-message-bridge": "^6.0|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^7.35|^8.14|^9.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.3|^10.5"
"phpunit/phpunit": "^9.3|^10.5|^11.0"
},
"autoload": {
"psr-4": {
Expand Down Expand Up @@ -66,6 +67,6 @@
"post-autoload-dump": "@prepare",
"prepare": "@php vendor/bin/testbench package:discover --ansi"
},
"minimum-stability": "dev",
"minimum-stability": "stable",
"prefer-stable": true
}
12 changes: 7 additions & 5 deletions database/factories/ClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use Laravel\Passport\Client;
use Laravel\Passport\Passport;

/**
Expand All @@ -13,11 +12,14 @@
class ClientFactory extends Factory
{
/**
* The name of the factory's corresponding model.
* Get the name of the model that is generated by the factory.
*
* @var string
* @return class-string<\Illuminate\Database\Eloquent\Model>
*/
protected $model = Client::class;
public function modelName()
{
return $this->model ?? Passport::clientModel();
}

/**
* Define the model's default state.
Expand Down Expand Up @@ -46,7 +48,7 @@ public function definition()
protected function ensurePrimaryKeyIsSet(array $data)
{
if (Passport::clientUuids()) {
$keyName = (new $this->model)->getKeyName();
$keyName = (new ($this->modelName()))->getKeyName();

$data[$keyName] = (string) Str::orderedUuid();
}
Expand Down
11 changes: 5 additions & 6 deletions src/Bridge/AccessToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ class AccessToken implements AccessTokenEntityInterface
/**
* Create a new token instance.
*
* @param string $userIdentifier
* @param array $scopes
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $client
* @return void
* @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes
*/
public function __construct($userIdentifier, array $scopes, ClientEntityInterface $client)
public function __construct(string|null $userIdentifier, array $scopes, ClientEntityInterface $client)
{
$this->setUserIdentifier($userIdentifier);
if (! is_null($userIdentifier)) {
$this->setUserIdentifier($userIdentifier);
}

foreach ($scopes as $scope) {
$this->addScope($scope);
Expand Down
37 changes: 14 additions & 23 deletions src/Bridge/AccessTokenRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,16 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface

/**
* The token repository instance.
*
* @var \Laravel\Passport\TokenRepository
*/
protected $tokenRepository;
protected TokenRepository $tokenRepository;

/**
* The event dispatcher instance.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;
protected Dispatcher $events;

/**
* Create a new repository instance.
*
* @param \Laravel\Passport\TokenRepository $tokenRepository
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function __construct(TokenRepository $tokenRepository, Dispatcher $events)
{
Expand All @@ -45,46 +37,45 @@ public function __construct(TokenRepository $tokenRepository, Dispatcher $events
/**
* {@inheritdoc}
*/
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
{
public function getNewToken(
ClientEntityInterface $clientEntity,
array $scopes,
string|null $userIdentifier = null
): AccessTokenEntityInterface {
return new Passport::$accessTokenEntity($userIdentifier, $scopes, $clientEntity);
}

/**
* {@inheritdoc}
*/
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity): void
{
$this->tokenRepository->create([
'id' => $accessTokenEntity->getIdentifier(),
'user_id' => $accessTokenEntity->getUserIdentifier(),
'client_id' => $accessTokenEntity->getClient()->getIdentifier(),
'id' => $id = $accessTokenEntity->getIdentifier(),
'user_id' => $userId = $accessTokenEntity->getUserIdentifier(),
'client_id' => $clientId = $accessTokenEntity->getClient()->getIdentifier(),
'scopes' => $this->scopesToArray($accessTokenEntity->getScopes()),
'revoked' => false,
'created_at' => new DateTime,
'updated_at' => new DateTime,
'expires_at' => $accessTokenEntity->getExpiryDateTime(),
]);

$this->events->dispatch(new AccessTokenCreated(
$accessTokenEntity->getIdentifier(),
$accessTokenEntity->getUserIdentifier(),
$accessTokenEntity->getClient()->getIdentifier()
));
$this->events->dispatch(new AccessTokenCreated($id, $userId, $clientId));
}

/**
* {@inheritdoc}
*/
public function revokeAccessToken($tokenId)
public function revokeAccessToken(string $tokenId): void
{
$this->tokenRepository->revokeAccessToken($tokenId);
}

/**
* {@inheritdoc}
*/
public function isAccessTokenRevoked($tokenId)
public function isAccessTokenRevoked(string $tokenId): bool
{
return $this->tokenRepository->isAccessTokenRevoked($tokenId);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Bridge/AuthCodeRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ class AuthCodeRepository implements AuthCodeRepositoryInterface
/**
* {@inheritdoc}
*/
public function getNewAuthCode()
public function getNewAuthCode(): AuthCodeEntityInterface
{
return new AuthCode;
}

/**
* {@inheritdoc}
*/
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity): void
{
$attributes = [
'id' => $authCodeEntity->getIdentifier(),
Expand All @@ -38,15 +38,15 @@ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
/**
* {@inheritdoc}
*/
public function revokeAuthCode($codeId)
public function revokeAuthCode(string $codeId): void
{
Passport::authCode()->where('id', $codeId)->update(['revoked' => true]);
}

/**
* {@inheritdoc}
*/
public function isAuthCodeRevoked($codeId)
public function isAuthCodeRevoked(string $codeId): bool
{
return Passport::authCode()->where('id', $codeId)->where('revoked', 1)->exists();
}
Expand Down
53 changes: 11 additions & 42 deletions src/Bridge/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,63 +4,32 @@

use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\ClientTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;

class Client implements ClientEntityInterface
{
use ClientTrait;

/**
* The client identifier.
*
* @var string
*/
protected $identifier;
use ClientTrait, EntityTrait;

/**
* The client's provider.
*
* @var string
*/
public $provider;
public ?string $provider;

/**
* Create a new client instance.
*
* @param string $identifier
* @param string $name
* @param string $redirectUri
* @param bool $isConfidential
* @param string|null $provider
* @return void
*/
public function __construct($identifier, $name, $redirectUri, $isConfidential = false, $provider = null)
{
$this->setIdentifier((string) $identifier);
public function __construct(
string $identifier,
string $name,
string $redirectUri,
bool $isConfidential = false,
?string $provider = null
) {
$this->setIdentifier($identifier);

$this->name = $name;
$this->isConfidential = $isConfidential;
$this->redirectUri = explode(',', $redirectUri);
$this->provider = $provider;
}

/**
* Get the client's identifier.
*
* @return string
*/
public function getIdentifier()
{
return (string) $this->identifier;
}

/**
* Set the client's identifier.
*
* @param string $identifier
* @return void
*/
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}
Loading