From 4b1df7fa420a3d1c6b8a54f068ad79e92c84b72d Mon Sep 17 00:00:00 2001 From: Aditya Ghaffar Date: Mon, 11 Dec 2023 02:46:13 +0700 Subject: [PATCH] feat: expiration by seconds --- config/sanctum.php | 2 ++ src/Guard.php | 4 ++-- tests/Feature/GuardTest.php | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/config/sanctum.php b/config/sanctum.php index 35d75b31..a1e6e444 100644 --- a/config/sanctum.php +++ b/config/sanctum.php @@ -44,6 +44,8 @@ | considered expired. This will override any values set in the token's | "expires_at" attribute, but first-party sessions are not affected. | + | To set the number of seconds, use decimal. + | */ 'expiration' => null, diff --git a/src/Guard.php b/src/Guard.php index 50f3c24c..b2b1333d 100644 --- a/src/Guard.php +++ b/src/Guard.php @@ -19,7 +19,7 @@ class Guard /** * The number of minutes tokens should be allowed to remain valid. * - * @var int + * @var int|float */ protected $expiration; @@ -156,7 +156,7 @@ protected function isValidAccessToken($accessToken): bool } $isValid = - (! $this->expiration || $accessToken->created_at->gt(now()->subMinutes($this->expiration))) + (! $this->expiration || $accessToken->created_at->gt(now()->subSeconds($this->expiration * 60))) && (! $accessToken->expires_at || ! $accessToken->expires_at->isPast()) && $this->hasValidProvider($accessToken->tokenable); diff --git a/tests/Feature/GuardTest.php b/tests/Feature/GuardTest.php index ab0102ef..07585eea 100644 --- a/tests/Feature/GuardTest.php +++ b/tests/Feature/GuardTest.php @@ -164,6 +164,39 @@ public function test_authentication_with_token_succeeds_if_expires_at_not_passed $this->assertInstanceOf(DateTimeInterface::class, $returnedUser->currentAccessToken()->last_used_at); } + public function test_authentication_with_token_succeeds_if_expires_at_not_passed_by_seconds() + { + $factory = Mockery::mock(AuthFactory::class); + + $expiration = 1 / 60 * 10; + $guard = new Guard($factory, $expiration, 'users'); + + $webGuard = Mockery::mock(stdClass::class); + + $factory->shouldReceive('guard') + ->with('web') + ->andReturn($webGuard); + + $webGuard->shouldReceive('user')->once()->andReturn(null); + + $request = Request::create('/', 'GET'); + $request->headers->set('Authorization', 'Bearer test'); + + $token = PersonalAccessTokenFactory::new()->for( + $user = UserFactory::new()->create(), + 'tokenable' + )->create([ + 'name' => 'Test', + 'expires_at' => now()->addSeconds(3), + ]); + + $returnedUser = $guard->__invoke($request); + + $this->assertEquals($user->id, $returnedUser->id); + $this->assertEquals($token->id, $returnedUser->currentAccessToken()->id); + $this->assertInstanceOf(DateTimeInterface::class, $returnedUser->currentAccessToken()->last_used_at); + } + public function test_authentication_is_successful_with_token_if_no_session_present() { $factory = Mockery::mock(AuthFactory::class);