thephpleague / oauth2-server

A spec compliant, secure by default PHP OAuth 2.0 Server
https://oauth2.thephpleague.com
MIT License
6.49k stars 1.12k forks source link

Intermittent BearerTokenValidator exceptions in the log #1278

Closed scottmetoyer closed 2 years ago

scottmetoyer commented 2 years ago

I'm seeing this error several times a day in our log:

[2022-04-11 14:21:24] production.ERROR: The resource owner or authorization server denied the request. {"exception":"[object] (League\\OAuth2\\Server\\Exception\\OAuthServerException(code: 9): The resource owner or authorization server denied the request. at /home/forge/store.scottmetoyer.com/vendor/league/oauth2-server/src/Exception/OAuthServerException.php:243)
[stacktrace]
#0 /home/forge/store.scottmetoyer.com/vendor/league/oauth2-server/src/AuthorizationValidators/BearerTokenValidator.php(111): League\\OAuth2\\Server\\Exception\\OAuthServerException::accessDenied()
#1 /home/forge/store.scottmetoyer.com/vendor/league/oauth2-server/src/ResourceServer.php(84): League\\OAuth2\\Server\\AuthorizationValidators\\BearerTokenValidator->validateAuthorization()
#2 /home/forge/store.scottmetoyer.com/vendor/laravel/passport/src/Guards/TokenGuard.php(204): League\\OAuth2\\Server\\ResourceServer->validateAuthenticatedRequest()
#3 /home/forge/store.scottmetoyer.com/vendor/laravel/passport/src/Guards/TokenGuard.php(147): Laravel\\Passport\\Guards\\TokenGuard->getPsrRequestViaBearerToken()
#4 /home/forge/store.scottmetoyer.com/vendor/laravel/passport/src/Guards/TokenGuard.php(110): Laravel\\Passport\\Guards\\TokenGuard->authenticateViaBearerToken()
#5 /home/forge/store.scottmetoyer.com/vendor/laravel/passport/src/PassportServiceProvider.php(309): Laravel\\Passport\\Guards\\TokenGuard->user()
#6 [internal function]: Laravel\\Passport\\PassportServiceProvider->Laravel\\Passport\\{closure}()
#7 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Auth/RequestGuard.php(58): call_user_func()
#8 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php(60): Illuminate\\Auth\\RequestGuard->user()
#9 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(63): Illuminate\\Auth\\RequestGuard->check()
#10 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(42): Illuminate\\Auth\\Middleware\\Authenticate->authenticate()
#11 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#12 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#13 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\\Pipeline\\Pipeline->then()
#14 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\\Routing\\Router->runRouteWithinStack()
#15 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\\Routing\\Router->runRoute()
#16 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\\Routing\\Router->dispatchToRoute()
#17 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\\Routing\\Router->dispatch()
#18 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#19 /home/forge/store.scottmetoyer.com/vendor/livewire/livewire/src/DisableBrowserCache.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#20 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Livewire\\DisableBrowserCache->handle()
#21 /home/forge/store.scottmetoyer.com/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(60): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#22 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Barryvdh\\Debugbar\\Middleware\\InjectDebugbar->handle()
#23 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#24 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#25 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#26 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#27 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#28 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#29 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#30 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#31 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#32 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#33 /home/forge/store.scottmetoyer.com/vendor/fruitcake/laravel-cors/src/HandleCors.php(52): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#34 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake\\Cors\\HandleCors->handle()
#35 /home/forge/store.scottmetoyer.com/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#36 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\\Proxy\\TrustProxies->handle()
#37 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#38 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\\Pipeline\\Pipeline->then()
#39 /home/forge/store.scottmetoyer.com/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#40 /home/forge/store.scottmetoyer.com/public/index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle()
#41 {main}

The majority of auth requests are going through just fine, this only pops up occasionally and after the users have successfully authenticated and performed a few actions through our API.

Are there any additional troubleshooting steps or ideas for figuring this out?

Sephster commented 2 years ago

Are you discarding the refresh tokens?

scottmetoyer commented 2 years ago

We're using this with Laravel Passport (password grant) and the refresh tokens are being saved in the oauth_refresh_tokens table.

Sephster commented 2 years ago

The reason I ask about discarding is sometimes, when you use a refresh token, it is then marked as invalid but due to connection issues, you might not receive the corresponding new access token.

When you go to re-use the refresh token, it is no longer valid and you end up having to request a brand new access token/refresh token combo.

We addressed this in the library, allowing you to retain refresh tokens indefinitely until they are manually invalidated. In the AuthorizationServer class there is a function called revokeRefreshTokens() that handles this functionality.

I've checked and it looks like Passport doesn't use this toggle at present. Maybe @driesvints would consider a PR for it. I hope that is of use. Alternatively you might be able to customise your Passport instance to set this boolean

driesvints commented 2 years ago

I'm not entirely sure what's needed for that but if you attempt a PR we can go from there.