Vue.js / Laravel - Handle logout correctly

16,174

Solution 1

Never used Laravel myself, but you should be able to handle logouts client side without needing to do anything in your backend. At the moment you remove auth token from local storage, so the user loses access to data that requires you to be logged in to get.

You probably call your getUser when you refresh the page and that's why you are only logged out then - you send empty token to your backend server, it can't find a user that's associated to it and returns an empty/default guest object. What's left to do is clear your user state after removing the token in your logout() function or send a request to your /get-user endpoint.

Solution 2

That's a bit old, however, I've just started with Laravel/Vue and managed to do this quite simple. Using the integrated auth from Laravel, you could just simulate the logout from app.blade.php like so:

<b-dropdown-item href="#" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">Sign Out</b-dropdown-item> //that's instead of a regular <a> tag
<b-form id="logout-form" action="logout" method="POST" style="display: none;">
   <input type="hidden" name="_token" :value="csrf">
</b-form>

You'll need to have the csrf token passed through data in your script in order for it to work like so:

export default {
 data() {
   return {
     csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content')
   }
 },
 methods: {
   submit : function(){
     this.$refs.form.submit();
   }
 }
}

As well as adding a meta csrf in your head (blade.php file) like so:

<meta name="csrf-token" content="{{ csrf_token()}}">

I'm assuming you'll be using the logout in your navbar .vue file

Solution 3

For my logout links I'd like to make a request to Laravel to invalidate the current user's (Passport JWT) token.

Here's how I'm doing it:

In my backend:

AuthController.php

I have a logout method:

  ...

  public function logout(Request $request) {
    $request->user()->token()->revoke();

    return response()->json([
       'message' => 'Successfully logged out'
    ]);
  }

routes/api.php

I have a route that can only be accessed by being authenticated.

Route::group(['middleware' => 'auth:api'], function() {
  ...

  Route::get('/logout', 'AuthController@logout');
});

My frontend:

For this I'm using Vue's single file components

App.vue

<template>
  <nav>
    <ul>
      ...
        <li v-if="isLoggedIn">
          <a id="logout-link" href="#" @click.prevent="logout">Logout</a>
        </li>
    </ul>
  </nav>
  ...
</template>

<script>
export default {
   ...
   methods: {
     logout(evt) {
       if(confirm("Are you sure you want to log out?")) {
         axios.get('api/logout').then(response => {
          localStorage.removeItem('auth_token');

          // remove any other authenticated user data you put in local storage

          // Assuming that you set this earlier for subsequent Ajax request at some point like so:
          // axios.defaults.headers.common['Authorization'] = 'Bearer ' + auth_token ;
          delete axios.defaults.headers.common['Authorization'];

          // If using 'vue-router' redirect to login page
          this.$router.go('/login');
        })
        .catch(error => {
          // If the api request failed then you still might want to remove
          // the same data from localStorage anyways
          // perhaps this code should go in a finally method instead of then and catch
          // methods to avoid duplication.
          localStorage.removeItem('auth_token');
          delete axios.defaults.headers.common['Authorization'];
          this.$router.go('/login');
        });       
       }
     }
   }
}
</script>

The point of this approach then is to invalidate the token on the back end upon logging out. Nevertheless, it might not be necessary to do this if the token has short expiration dates.

Solution 4

To logout install axios and do the rest code in Laravel 6* / 7* / 8*

npm install axios

the trigger this code when you click on logout

axios.post("logout").then(response => { 
   console.log(response);
})
.catch(error => {
   console.log(error);
});
Share:
16,174
oliverbj
Author by

oliverbj

Updated on June 23, 2022

Comments

  • oliverbj
    oliverbj almost 2 years

    I am currently trying to create a simple SPA using Vue and Laravel. I've got the basics to work - users can register and login.

    I just can't figure out how to create a logout function.

    This is what I currently have:

    AuthController.php:

    public function logout()
    {
            $accessToken = auth()->user()->token();
    
            $refreshToken = DB::table('oauth_refresh_tokens')
            ->where('access_token_id', $accessToken->id)
            ->update([
                'revoked' => true
            ]);
    
            $accessToken->revoke();
    
            return response()->json(['status' => 200]);
    }
    

    routes/api.php:

    Route::middleware('auth:api')->group(function () {
        Route::post('/logout', 'API\AuthController@logout');
        Route::get('/get-user', 'API\AuthController@getUser');
    });
    

    Right now, this is what I have tried to do:

    Layout.vue:

    methods: {
                logout() {
                    axios.post('/api/logout').then(response => {
                        this.$router.push("/login")
    
                    }).catch(error => {
                        location.reload();
                    });
                }
     }
    

    Which calls my logout function in Auth.js:

    logout() {
        localStorage.removeItem('token')
        localStorage.removeItem('expiration')
    }
    

    However, when users click on the logout function, they are not logged out immediately (redirected to the login page) - they can still browse "user only pages".

    I have to refresh the page before I am properly logged out.

    Can anyone assist me with this? Is this even the right approach to a "secure" logout function?

  • oliverbj
    oliverbj over 5 years
    I would prefer handling everything in Vue
  • oliverbj
    oliverbj over 5 years
    Sounds correct. Any idea on how to implement this? An example? Sorry but I’m quite new to Vue
  • dziraf
    dziraf over 5 years
    Just do something like axios.get('/api/get-user').then(response => { <your_user_data_state> = response.data }).catch(err => console.log(err.response.data)) after localStorage.removeItem('expiration')
  • dziraf
    dziraf over 5 years
    You don't need a logout route to handle logouts; you need to reset user state which you now do on page refresh.