diff --git a/database/factories/PassportClientFactory.php b/database/factories/PassportClientFactory.php index a84c4c6ab..f529b9f04 100644 --- a/database/factories/PassportClientFactory.php +++ b/database/factories/PassportClientFactory.php @@ -24,3 +24,10 @@ 'password_client' => true, ]; }); + +$factory->state(Client::class, 'client_credentials', function (Faker $faker) { + return [ + 'personal_access_client' => false, + 'password_client' => false, + ]; +}); diff --git a/tests/Feature/AccessTokenControllerTest.php b/tests/Feature/AccessTokenControllerTest.php index 48697da62..67ae3acee 100644 --- a/tests/Feature/AccessTokenControllerTest.php +++ b/tests/Feature/AccessTokenControllerTest.php @@ -41,6 +41,95 @@ protected function getUserClass() return User::class; } + public function testGettingAccessTokenWithClientCredentialsGrant() + { + $this->withoutExceptionHandling(); + + $user = new User(); + $user->email = 'foo@gmail.com'; + $user->password = $this->app->make(Hasher::class)->make('foobar123'); + $user->save(); + + /** @var Client $client */ + $client = $this->app->make(Factory::class)->of(Client::class)->state('client_credentials')->create(['user_id' => $user->id]); + + $response = $this->post( + '/oauth/token', + [ + 'grant_type' => 'client_credentials', + 'client_id' => $client->id, + 'client_secret' => $client->secret, + ] + ); + + $response->assertOk(); + + $response->assertHeader('pragma', 'no-cache'); + $response->assertHeader('cache-control', 'no-store, private'); + $response->assertHeader('content-type', 'application/json; charset=UTF-8'); + + $decodedResponse = $response->decodeResponseJson(); + + $this->assertArrayHasKey('token_type', $decodedResponse); + $this->assertArrayHasKey('expires_in', $decodedResponse); + $this->assertArrayHasKey('access_token', $decodedResponse); + $this->assertSame('Bearer', $decodedResponse['token_type']); + $expiresInSeconds = 31536000; + $this->assertEqualsWithDelta($expiresInSeconds, $decodedResponse['expires_in'], 5); + + $jwtAccessToken = (new Parser())->parse($decodedResponse['access_token']); + $this->assertTrue($this->app->make(ClientRepository::class)->findActive($jwtAccessToken->getClaim('aud'))->is($client)); + + $token = $this->app->make(TokenRepository::class)->find($jwtAccessToken->getClaim('jti')); + $this->assertInstanceOf(Token::class, $token); + $this->assertTrue($token->client->is($client)); + $this->assertFalse($token->revoked); + $this->assertNull($token->name); + $this->assertNull($token->user_id); + $this->assertLessThanOrEqual(5, CarbonImmutable::now()->addSeconds($expiresInSeconds)->diffInSeconds($token->expires_at)); + } + + public function testGettingAccessTokenWithClientCredentialsGrantInvalidClientSecret() + { + $user = new User(); + $user->email = 'foo@gmail.com'; + $user->password = $this->app->make(Hasher::class)->make('foobar123'); + $user->save(); + + /** @var Client $client */ + $client = $this->app->make(Factory::class)->of(Client::class)->state('client_credentials')->create(['user_id' => $user->id]); + + $response = $this->post( + '/oauth/token', + [ + 'grant_type' => 'client_credentials', + 'client_id' => $client->id, + 'client_secret' => $client->secret.'foo', + ] + ); + + $response->assertStatus(401); + + $response->assertHeader('cache-control', 'no-cache, private'); + $response->assertHeader('content-type', 'application/json'); + + $decodedResponse = $response->decodeResponseJson(); + + $this->assertArrayNotHasKey('token_type', $decodedResponse); + $this->assertArrayNotHasKey('expires_in', $decodedResponse); + $this->assertArrayNotHasKey('access_token', $decodedResponse); + + $this->assertArrayHasKey('error', $decodedResponse); + $this->assertSame('invalid_client', $decodedResponse['error']); + $this->assertArrayHasKey('error_description', $decodedResponse); + $this->assertSame('Client authentication failed', $decodedResponse['error_description']); + $this->assertArrayNotHasKey('hint', $decodedResponse); + $this->assertArrayHasKey('message', $decodedResponse); + $this->assertSame('Client authentication failed', $decodedResponse['message']); + + $this->assertSame(0, Token::count()); + } + public function testGettingAccessTokenWithPasswordGrant() { $this->withoutExceptionHandling();