diff --git a/src/ClientRepository.php b/src/ClientRepository.php index 5fc2fab0a..4d86d9701 100644 --- a/src/ClientRepository.php +++ b/src/ClientRepository.php @@ -98,19 +98,20 @@ public function forUser($userId) */ public function activeForUser($userId) { - return $this->forUser($userId)->reject(function ($client) { - return $client->revoked; - })->values(); + return $this->forUser($userId) + ->reject(fn ($client) => $client->revoked) + ->values(); } /** * Get the personal access token client for the application. * + * @param string|null $provider * @return \Laravel\Passport\Client * * @throws \RuntimeException */ - public function personalAccessClient() + public function personalAccessClient($provider = null) { if ($this->personalAccessClientId) { return $this->find($this->personalAccessClientId); @@ -118,11 +119,18 @@ public function personalAccessClient() $client = Passport::personalAccessClient(); - if (! $client->exists()) { + $personalAccessClient = $client + ->when($provider, function ($query, $provider) { + $query->whereRelation('client', 'provider', $provider); + }) + ->latest($client->getKeyName()) + ->first(); + + if (is_null($personalAccessClient)) { throw new RuntimeException('Personal access client not found. Please create one.'); } - return $client->orderBy($client->getKeyName(), 'desc')->first()->client; + return $client->client; } /** diff --git a/src/HasApiTokens.php b/src/HasApiTokens.php index f68bc1ee0..58ec67081 100644 --- a/src/HasApiTokens.php +++ b/src/HasApiTokens.php @@ -30,7 +30,11 @@ public function clients() */ public function tokens() { - return $this->hasMany(Passport::tokenModel(), 'user_id')->orderBy('created_at', 'desc'); + return $this->hasMany(Passport::tokenModel(), 'user_id') + ->when($this->getProvider(), function ($query, $provider) { + $query->whereRelation('client', 'provider', $provider); + }) + ->latest('created_at'); } /** @@ -64,7 +68,7 @@ public function tokenCan($scope) public function createToken($name, array $scopes = []) { return Container::getInstance()->make(PersonalAccessTokenFactory::class)->make( - $this->getKey(), $name, $scopes + $this->getKey(), $name, $scopes, $this->getProvider(), ); } @@ -80,4 +84,24 @@ public function withAccessToken($accessToken) return $this; } + + /** + * Get the provider name of the model. + * + * @return string|null + */ + protected function getProvider() + { + foreach (config('auth.providers', []) as $name => $config) { + if ($config['driver'] == 'eloquent' && is_a($this, $config['model'])) { + return $name; + } + + if ($config['driver'] == 'database' && $this->getTable() == $config['table']) { + return $name; + } + } + + return null; + } } diff --git a/src/PersonalAccessTokenFactory.php b/src/PersonalAccessTokenFactory.php index 15ac840ad..4ee9ee302 100644 --- a/src/PersonalAccessTokenFactory.php +++ b/src/PersonalAccessTokenFactory.php @@ -64,12 +64,13 @@ public function __construct(AuthorizationServer $server, * @param mixed $userId * @param string $name * @param array $scopes + * @param string|null $provider * @return \Laravel\Passport\PersonalAccessTokenResult */ - public function make($userId, $name, array $scopes = []) + public function make($userId, $name, array $scopes = [], $provider = null) { $response = $this->dispatchRequestToAuthorizationServer( - $this->createRequest($this->clients->personalAccessClient(), $userId, $scopes) + $this->createRequest($this->clients->personalAccessClient($provider), $userId, $scopes) ); $token = tap($this->findAccessToken($response), function ($token) use ($userId, $name) { diff --git a/tests/Unit/HasApiTokensTest.php b/tests/Unit/HasApiTokensTest.php index 2abf68c95..9347acc6a 100644 --- a/tests/Unit/HasApiTokensTest.php +++ b/tests/Unit/HasApiTokensTest.php @@ -2,6 +2,7 @@ namespace Laravel\Passport\Tests\Unit; +use Illuminate\Config\Repository; use Illuminate\Container\Container; use Laravel\Passport\HasApiTokens; use Laravel\Passport\PersonalAccessTokenFactory; @@ -31,8 +32,9 @@ public function test_token_can_be_created() { $container = new Container; Container::setInstance($container); + $container->instance('config', new Repository); $container->instance(PersonalAccessTokenFactory::class, $factory = m::mock()); - $factory->shouldReceive('make')->once()->with(1, 'name', ['scopes']); + $factory->shouldReceive('make')->once()->with(1, 'name', ['scopes'], null); $user = new HasApiTokensTestStub; $user->createToken('name', ['scopes']); diff --git a/tests/Unit/PassportTest.php b/tests/Unit/PassportTest.php index b6e69e2ad..a49abbc8a 100644 --- a/tests/Unit/PassportTest.php +++ b/tests/Unit/PassportTest.php @@ -50,7 +50,7 @@ public function test_personal_access_client_instance_can_be_created() public function test_missing_personal_access_client_is_reported() { - $this->expectException('RuntimeException'); + $this->expectException('Error'); Passport::usePersonalAccessClientModel(PersonalAccessClientStub::class); @@ -89,10 +89,6 @@ public function test_refresh_token_model_can_be_changed() class PersonalAccessClientStub { - public function exists() - { - return false; - } } class RefreshTokenStub diff --git a/tests/Unit/PersonalAccessTokenFactoryTest.php b/tests/Unit/PersonalAccessTokenFactoryTest.php index c35127104..965f00244 100644 --- a/tests/Unit/PersonalAccessTokenFactoryTest.php +++ b/tests/Unit/PersonalAccessTokenFactoryTest.php @@ -55,6 +55,38 @@ public function test_access_token_can_be_created() $this->assertInstanceOf(PersonalAccessTokenResult::class, $result); } + + public function test_access_token_can_be_created_with_provider() + { + $server = m::mock(AuthorizationServer::class); + $clients = m::mock(ClientRepository::class); + $tokens = m::mock(TokenRepository::class); + $jwt = m::mock(Parser::class); + + $provider = 'some_provider'; + + $factory = new PersonalAccessTokenFactory($server, $clients, $tokens, $jwt); + + $clients->shouldReceive('personalAccessClient')->with($provider)->andReturn(new PersonalAccessTokenFactoryTestClientStub); + $server->shouldReceive('respondToAccessTokenRequest')->andReturn($response = m::mock()); + $response->shouldReceive('getBody->__toString')->andReturn(json_encode([ + 'access_token' => 'foo', + ])); + + $parsedToken = new PlainToken( + new DataSet([], ''), + new DataSet([RegisteredClaims::ID => 'token'], ''), + new Signature('', '') + ); + + $jwt->shouldReceive('parse')->with('foo')->andReturn($parsedToken); + $tokens->shouldReceive('find')->with('token')->andReturn($foundToken = new PersonalAccessTokenFactoryTestModelStub); + $tokens->shouldReceive('save')->with($foundToken); + + $result = $factory->make(1, 'token', ['scopes'], $provider); + + $this->assertInstanceOf(PersonalAccessTokenResult::class, $result); + } } class PersonalAccessTokenFactoryTestClientStub extends Client