Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logout issue with Laravel JWT-auth authentication

I'm use jwt-auth to make a RESTful auth resource in my API. When a client app calls the login resource, case user is logged, your current token must be invalidated and so a new token generated.

But case the current token is blacklisted a TokenBlacklistedException is thrown.

How to verify if a token is blacklisted? Or how to correct implement an user "logout"? I try to found on jwt-auth API source but not exists a getToken()->isBlacklisted() or parseToken()->isBlacklisted() or some validator to implement it.

Ever token is invalid parseToken() throws a TokenBlacklistedException, so an isBlacklisted method is a good way to verify if token is valid before invalidate a token.

INFO:

The bellow code verify if payload is invalid, thrown the TokenBlacklistedException if is invalid:

if(
    false === \Tymon\JWTAuth\Blacklist::has(
        \Tymon\JWTAuth\Facades\JWTAuth::getPayload($token)
    )
) {
     \Tymon\JWTAuth\Facades\JWTAuth::parseToken()->invalidate();
}

How to verify like:

if(false ===\Tymon\JWTAuth\Facades\JWTAuth::parseToken()->isBlacklisted()) {
    // invalidate...
}
like image 664
Maykonn Avatar asked Apr 14 '15 15:04

Maykonn


People also ask

How do you handle JWT logout?

Okay, so normally the client side stores the token somewhere while using JWT authentication, and attaches it to any request that needs authentication. Thus, the first thing to do when logging out is simply delete the token that you saved on the client (i.e. local storage browser).

Does laravel use JWT?

JSON web token (JWT) authentication is used to verify ownership of JSON data. JWT is not encryption, rather it determines if the data can be trusted because its ownership is verified.

Is JWT Auth safe?

It's an encoded, URL-safe string that can contain an unlimited amount of data (unlike a cookie) and is cryptographically signed. When a server receives a JWT, it can guarantee the data it contains can be trusted because it's signed by the source. No middleman can modify a JWT once it's sent.


2 Answers

You can simply destroy the session on the client side when they logout and invalidate the token on the backend, you shouldn't need to use the blacklist.

Technically destroying the token on the client side will be enough, but for session hijacking, invalidating it on the backend is a good idea too.

If you are invalidating, you'll need to destroy the token after you get your response from Laravel.


     JWTAuth::invalidate(JWTAuth::getToken());

Then on angular side

function logout()
{ 
    UserService.logout().$promise.then(function() {
        $cookieStore.remove('userToken');
        // redirect or whatever 
    });
}

One way you can handle JWT exceptions is to setup an EventServiceProvider in laravel, here is what mine looks like:

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider {

    /**
     * The event handler mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'tymon.jwt.valid' => [
            'App\Events\JWTEvents@valid',
        ],
        'tymon.jwt.user_not_found' => [
            'App\Events\JWTEvents@notFound'
        ],
        'tymon.jwt.invalid' => [
            'App\Events\JWTEvents@invalid'  
        ],
        'tymon.jwt.expired' => [
            'App\Events\JWTEvents@expired'  
        ],
        'tymon.jwt.absent' => [
            'App\Events\JWTEvents@missing'
        ]
    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);

        //
    }
}

You'll register that in your app.php.

Then I implement the JWTEvents class with methods for each event.

class JWTEvents extends Event {
    
    // Other methods        

    public function invalid()
    {
        return response()->json(['error' => 'Token Invalid'], 401);
        die();
    }
}

Important thing to note is that we are catching the JWT exceptions and returning a json response with a specific status code.

On the angular side, I have in my httpInterceptor class, catches for these http status codes.

angular.module('ngApp')
    .factory('httpInterceptor', function($q, $log, $cookieStore, $rootScope, Response) {
        return {
            
            request: function(config) {
                // Where you add the token to each request
            },
            
            responseError: function(response) {

                // Check if response code is 401 (or whatever)
                if (response.status === 401) {
                    // Do something to log user out & redirect.
                    $rootScope.$broadcast('invalid.token');
                }
            }
        }
    });
like image 102
Matthew Brown Avatar answered Sep 25 '22 08:09

Matthew Brown


This works for me.

public function logout( Request $request ) {

        $token = $request->header( 'Authorization' );

        try {
            JWTAuth::parseToken()->invalidate( $token );

            return response()->json( [
                'error'   => false,
                'message' => trans( 'auth.logged_out' )
            ] );
        } catch ( TokenExpiredException $exception ) {
            return response()->json( [
                'error'   => true,
                'message' => trans( 'auth.token.expired' )

            ], 401 );
        } catch ( TokenInvalidException $exception ) {
            return response()->json( [
                'error'   => true,
                'message' => trans( 'auth.token.invalid' )
            ], 401 );

        } catch ( JWTException $exception ) {
            return response()->json( [
                'error'   => true,
                'message' => trans( 'auth.token.missing' )
            ], 500 );
        }
    }
like image 37
Usama Munir Avatar answered Sep 26 '22 08:09

Usama Munir