jwt-auth
jwt-auth copied to clipboard
Token immediately blacklisted
I'm upgrading my Laravel 5.2 app to Lumen 5.4 and have managed to repair my app to a point where I can at least log in again ;)
So on login, I get a token back and my Angular app stores it and makes 3 API requests with it. These all work perfectly.
Then I click something to make another request. This request fails with:
The token has been blacklisted
I can confirm the correct header is being sent:
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9............
I get 2 stack traces... 1/2 is this:
TokenBlacklistedException in Manager.php line 97:
The token has been blacklisted
in Manager.php line 97
at Manager->decode(object(Token)) in JWT.php line 183
at JWT->getPayload() in JWTAuth.php line 60
at JWTAuth->authenticate() in BaseMiddleware.php line 69
at BaseMiddleware->authenticate(object(Request)) in Authenticate.php line 30
at Authenticate->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in RoutesRequests.php line 779
at Application->sendThroughPipeline(array('Tymon\\JWTAuth\\Http\\Middleware\\Authenticate', 'Tymon\\JWTAuth\\Http\\Middleware\\RefreshToken'), object(Closure)) in RoutesRequests.php line 625
at Application->handleFoundRoute(array(true, array('uses' => 'App\\Http\\Controllers\\AuctionController@index', 'middleware' => array('jwt.auth', 'jwt.refresh')), array())) in RoutesRequests.php line 528
at Application->Laravel\Lumen\Concerns\{closure}() in RoutesRequests.php line 782
at Application->sendThroughPipeline(array(), object(Closure)) in RoutesRequests.php line 534
at Application->dispatch(null) in RoutesRequests.php line 475
at Application->run() in index.php line 35
Then 2/2 is this:
UnauthorizedHttpException in BaseMiddleware.php line 71:
The token has been blacklisted
in BaseMiddleware.php line 71
at BaseMiddleware->authenticate(object(Request)) in Authenticate.php line 30
at Authenticate->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in RoutesRequests.php line 779
at Application->sendThroughPipeline(array('Tymon\\JWTAuth\\Http\\Middleware\\Authenticate', 'Tymon\\JWTAuth\\Http\\Middleware\\RefreshToken'), object(Closure)) in RoutesRequests.php line 625
at Application->handleFoundRoute(array(true, array('uses' => 'App\\Http\\Controllers\\AuctionController@index', 'middleware' => array('jwt.auth', 'jwt.refresh')), array())) in RoutesRequests.php line 528
at Application->Laravel\Lumen\Concerns\{closure}() in RoutesRequests.php line 782
at Application->sendThroughPipeline(array(), object(Closure)) in RoutesRequests.php line 534
at Application->dispatch(null) in RoutesRequests.php line 475
at Application->run() in index.php line 35
As you can see in there, I am using jwt.auth
and jwt.refresh
middleware...
$app->group(['prefix' => 'api/v1'], function() use ($app) {
$app->post('login', 'AuthController@login');
$app->group(['middleware' => ['jwt.auth', 'jwt.refresh']], function() use ($app) {
...
...
Any tips?
Note: I can make the error go away by adding this to my .env
:
JWT_BLACKLIST_ENABLED=false
But this does not feel like a "fix"... This feels like I have just made the problem go away without actually solving the cause ;)
Hi @njt1982 , I am no expert, but I was just poking around in the code in this area. And the code that does the refresh (Manager->refresh) will blacklist the token immediately if you have that enabled, making the tokens "one use only".
if ($this->blacklistEnabled) {
// invalidate old token
$this->invalidate($token, $forceForever);
}
The refresh middleware seems to only be something you would use if you were doing one use tokens.
Again, I'm no expert, currently poking around the code trying to figure out the right way to add refresh to my project.
i have this issue too
@njt1982 Are you storing the refreshed token?
Encountered the same problem, @njt1982 don't konw if this is still a problem, but for anyone else in this situation.
From the wiki
RefreshToken This middleware will again try to parse the token from the request, and in turn, will refresh the token (thus invalidating the old one) and return it as part of the next response. This essentially yields a single use token flow, which reduces the window of attack if a token is compromised since it is only valid for the single request.
So it is by design.
From my understanding, you won't be able to combine jwt.auth
and jwt.refresh
for the same route, that's what I was trying to do at least. Use only jwt.auth
and once your frontend detects that the token is invalid, call a route to refresh it, using the refresh middleware or directly the refresh function from the manager.
I was having the same issue. Was able to overcome it not by setting
JWT_BLACKLIST_ENABLED=false
Like @njt1982 mentioned as that would open up a vulnerability but I set the blacklist_grace_period
to 30
for 30 seconds
JWT_BLACKLIST_GRACE_PERIOD=30
Solved the issue of tokens dying for me and kept the security of having a blacklist
Okay this only fixed the issue for 30 seconds for me delaying the inevitable 401 - Token has been black listed
I now have two options as I see it.
- make a custom refresh middleware or closure where the refresh is called once and simple refreshes the token but doesn't blacklist it straight away
- refresh after or before every request
Thoughts?
Okay the solution for me was the following. I was even able to change the JWT_BLACKLIST_GRACE_PERIOD
back to 0
.
I changed my refresh api endpoint from
$api->get('refresh', [ 'middleware' => 'jwt.refresh',
function() {
return response()
->json([ 'message' => 'Token refreshed!' ]);
}
]);
to
$api->get('refresh', [ 'middleware' => 'jwt.refresh',
function() {
return response()
->json([ 'message' => 'Token refreshed!' ])
->header('Cache-Control', 'no-cache, no-store, must-revalidate');
}
]);
This prevents the endpoint being cached by the browser which means that the new/refreshed token is always received.
having all of these issues as well, @garhbod's cache method sort of worked but I can still get my token blacklisted sometimes when trying to refresh it.
@acidjazz What frontend are you using? Are multiple requests happening at once?
@garhbod nuxtjs, I don't think so, I can duplicate the blacklisting event by manually logging in, waiting for it to expire and hitting /refresh either with my browser or postman
please note that you can change config options in your codes in run time. I used this code and this was a solution for me:
config([
'jwt.blacklist_enabled' => true
]);
auth()->logout();
JWTAuth::invalidate(JWTAuth::parseToken());
please note that you can change config options in your codes in run time. I used this code and this was a solution for me:
config([ 'jwt.blacklist_enabled' => true ]); auth()->logout(); JWTAuth::invalidate(JWTAuth::parseToken());
@ivahidmontazer where to change there ?
please note that you can change config options in your codes in run time. I used this code and this was a solution for me:
config([ 'jwt.blacklist_enabled' => true ]); auth()->logout(); JWTAuth::invalidate(JWTAuth::parseToken());
@ivahidmontazer where to change there ?
You can change this config in your controllers or everywhere else, run time .
I have used this but not work
On Sat, Dec 15, 2018, 02:50 Vahid Montazer <[email protected] wrote:
please note that you can change config options in your codes in run time. I used this code and this was a solution for me:
config([ 'jwt.blacklist_enabled' => true ]); auth()->logout(); JWTAuth::invalidate(JWTAuth::parseToken());
@ivahidmontazer https://github.com/ivahidmontazer where to change there ?
You can change this config in your controllers or everywhere else, run time .
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/tymondesigns/jwt-auth/issues/983#issuecomment-447489465, or mute the thread https://github.com/notifications/unsubscribe-auth/Aj_EwctcWst5U6kAuf5d2cha4Nhxottlks5u5B0ZgaJpZM4LwqTX .
I have used this but not work … On Sat, Dec 15, 2018, 02:50 Vahid Montazer @.*** wrote: please note that you can change config options in your codes in run time. I used this code and this was a solution for me: config([ 'jwt.blacklist_enabled' => true ]); auth()->logout(); JWTAuth::invalidate(JWTAuth::parseToken()); @ivahidmontazer https://github.com/ivahidmontazer where to change there ? You can change this config in your controllers or everywhere else, run time . — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#983 (comment)>, or mute the thread https://github.com/notifications/unsubscribe-auth/Aj_EwctcWst5U6kAuf5d2cha4Nhxottlks5u5B0ZgaJpZM4LwqTX .
I had same problem specially when using multi auth with jwt. You can use a try
, catch
. when exception happens you can return 'You have logged out successfully';
in catch section.
I know this way user will not actually be logged out, but only solution I have found, was this!
nothing work i am using this code in my controller on run time
try
{
config([
'jwt.blacklist_enabled' => true
]);
\Cookie::forget(JWTAuth::parseToken());
auth()->logout();
JWTAuth::invalidate(JWTAuth::parseToken());
return response()->json(['message' => 'Successfully logged out']);
}
catch (Exception $e)
{
return response()->json(['message' => 'There is something wrong try again']);
}
nothing work i am using this code in my controller on run time
try { config([ 'jwt.blacklist_enabled' => true ]); \Cookie::forget(JWTAuth::parseToken()); auth()->logout(); JWTAuth::invalidate(JWTAuth::parseToken()); return response()->json(['message' => 'Successfully logged out']); } catch (Exception $e) { return response()->json(['message' => 'There is something wrong try again']); }
I set return response()->json(['message' => 'Successfully logged out']);
in catch
section not in try
section. I know this way user will not be logged out, but I didn't fount any other solution.
then what is the good of using
return response()->json(['message' => 'Successfully logged out']);
this code is catch section this way it shows only logout message my aim is not to show only message but logout the user as well what a funny answer it is but thanks for your response it will never work.
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Yes, it's still relevant and not fixed.
O opened PR #2139 to try to solve this issue and mitigate this exception and make it optional for us.
@tymondesigns can you review my PR #2139?
Thank you.