Quasar(0.14.x) Starter with JWT Authentication ( Laravel Backend 5.4 )



  • Hello guys!

    I created a starter kit that uses the JSON Web Token authentication system.

    You can find the code for frontend here and for the backend here

    Index

    Login

    Main


  • Admin

    Good job! I’m soon gonna improve the CLI on starter kits and we can include this one too.



  • Updated frontend on latest quasar version ( 0.13.9 )
    Updated backend on latest Laravel version (5.4)
    Added refresh token functionality



  • This post is deleted!


  • @Sponz
    Awesome. This has been helpful - thank you!
    Curious, how come you went with full blown Laravel vs using Lumen for the backend?



  • @Sponz Why didn’t you go for passport instead of your own JWT Authentication without Oauth2



  • @Ivar_Smits
    I think Laravel Passport isn’t really built for creating a token through login credentials.
    See this thread for a long discussion on the topic.
    JWT Auth is better for this.



  • Updated on latest version



  • @Sponz cool thanks!



  • @Sponz
    I’m super interested in this topic.

    I don’t think there’s any easy solution to this yet at all. If there is one I’d love to have a look.

    Now I’m doing A LOT of things manually:

    Backend

    I had to manually redirect api calls with options routes. I don’t know why but none of the CORS helper packages of Laravel that use júst middleware worked…

    Route::domain('api'.env('SESSION_DOMAIN'))
    	->group(function () {
    		Route::options('auth','CORSHelperController@handleCORS');
    		Route::options('register','CORSHelperController@handleCORS');
    		Route::options('logout','CORSHelperController@handleCORS');
    		Route::options('items','CORSHelperController@handleCORS');
    		Route::options('refreshToken','CORSHelperController@handleCORS');
    });
    Route::domain('api'.env('SESSION_DOMAIN'))
    	->middleware(['cors','api'])
    	->group(function () {
    		Route::post('auth','AuthenticateController@login');
    		Route::post('register','AuthenticateController@register');
    		Route::post('logout','AuthenticateController@logout');
    		Route::post('refreshToken','AuthenticateController@refreshToken');
    });
    

    I set up a refresh token route like so:

        public function refreshToken(Request $request)
        {
            $newToken = JWTAuth::refresh($request->only('token')['token']);
            $minutes = $path = $domain = null;
            $domain = 'http://localhost:8080';
            $secure = $httpOnly = true;
            return response($newToken)
    		        ->header('Set-Cookie', 'token='.$newToken.'; Secure; HttpOnly;');
        }
    

    Save the token as a secure cookie.

    Front End:

    1. JWT auth has only 1 kind of tokens. Access tokens. You do not need special “refresh tokens” as you can use the expired access tokens to refresh and receive a new token.
    2. Set the ttl short to eg. 1 day.
    3. you can refresh your token even after it’s expired with the above route.
    4. Save the token request date: new Date() in your SPA together with the token.
    5. In this case, if an api call is made and the token is expired (more than 24 hours has passed) the api calls won’t work. Therefore: on every API call just do a quick check, if the difference between new Date() and the token request date is bigger than 24 hours or not.
    6. In case more than 24 hours have passed, intercept the api call, first make a “refreshToken api call” → see 3) and then AFTERWARDS make the api call with the refreshed token.
      In my case, every API call does this:
    let now = new Date();
    let diff = getDateDiff(now, state.tokenTimeStamp, 'minutes');
    let tokenLifeSpan = 1439; // 1 day - 1 min
    if (diff > tokenLifeSpan)
    {
        if (window.refreshingToken)
        { 
            // this is to prevent an endless loop
            console.log('refreshingToken...');
            return;
        }
        window.refreshingToken = true;
    
        console.log(`old Token: ${state.token}`);
        console.log(`old Token Date: ${state.tokenTimeStamp}`);
        // here I start refreshing the token:
        axios.post(apiBaseURL+'refreshToken', {token:state.token})
        .then(({data}) => {
            window.axios.defaults.headers.common = {
                'X-Requested-With': 'XMLHttpRequest',
                'Authorization': "Bearer " + data ,
            };
            state.token = data;
            state.tokenTimeStamp = new Date();
            
            console.log(`new Token: ${state.token}`);
            console.log(`new Token Date: ${state.tokenTimeStamp}`);
            window.refreshingToken = false;
            // then I do the API call once more, after having made sure the new token is set properly:
            dispatch('patch', {id, field, value});
        });
        console.log('stop here');
        return;
    }
    

    Now it’s #6 here I’m having trouble with as it’s not manually implemented on each API call. I’m having trouble finding a way to keep this code DRY…


Log in to reply
 

Looks like your connection to Quasar Framework was lost, please wait while we try to reconnect.