Managing logout feature effectively in Vue.js/LaravelEnsuring proper logout functionality

I'm currently in the process of building a simple SPA with Vue and Laravel. So far, I've managed to set up user registration and login functionalities.

However, one thing that's stumping me is how to implement a logout feature.

Here's what my current setup looks like:

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');
});

So far, here's what I've attempted:

Layout.vue:

methods: {
            logout() {
                axios.post('/api/logout').then(response => {
                    this.$router.push("/login")

                }).catch(error => {
                    location.reload();
                });
            }
 }

This method invokes my logout function in Auth.js:

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

Unfortunately, when users click on the logout button, they're not immediately logged out (or redirected to the login page) – they can still access "user only pages". A manual page refresh seems to be required for proper log out.

Can someone offer guidance on this? Is this the correct way to implement a secure logout mechanism?

Answer №1

Although it may be considered outdated, I recently delved into Laravel and Vue development and successfully implemented a simple logout feature. By leveraging the built-in authentication system of Laravel, you can mimic the logout action in app.blade.php as follows:

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

To make this functionality work, ensure that the csrf token is accessible within your script data object like so:

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

Additionally, include a meta csrf tag in the head section of your blade.php file:

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

This setup assumes that you will integrate the logout functionality in your navbar .vue component.

Answer №2

Although I haven't personally worked with Laravel, it seems like handling logouts on the client side is feasible without requiring any backend changes. By removing the auth token from local storage, the user will no longer have access to protected data.

It appears that when you refresh the page, your getUser function is called, resulting in being logged out only at that moment. This occurs because an empty token is sent to your backend server, which is unable to find a user associated with it and returns a default guest object. To complete the logout process, make sure to clear the user state after deleting the token in your logout() function or send a request to the /get-user endpoint.

Answer №3

For logging out, make sure to have axios installed and then follow the steps below in Laravel versions 6*, 7*, or 8*:

npm install axios

Lastly, use this code to trigger the logout function upon clicking:

axios.post("logout").then(response => { 
   console.log(response);
})
.catch(error => {
   console.log(error);
});

Answer №4

When it comes to handling logout links, my preference is to send a request to Laravel in order to invalidate the current user's (Passport JWT) token.

Here's the method I am using:

On the backend:

AuthController.php

Within this file, I have created a logout method:

  ...

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

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

routes/api.php

I have set up a route that requires authentication for access.

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

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

On the frontend:

In this case, I am utilizing 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 stored in local storage

          // If you previously set this for subsequent Ajax requests:
          // axios.defaults.headers.common['Authorization'] = 'Bearer ' + auth_token ;
          delete axios.defaults.headers.common['Authorization'];

          // Redirect to login page if using 'vue-router'
          this.$router.go('/login');
        })
        .catch(error => {
          // Even if the api request fails, consider clearing
          // the same data from localStorage
          // This can be done in a finally method to avoid duplication
          localStorage.removeItem('auth_token');
          delete axios.defaults.headers.common['Authorization'];
          this.$router.go('/login');
        });       
       }
     }
   }
}
</script>

The purpose of this approach is to revoke the token on the backend when logging out. However, this step may not be necessary if the token has a short expiration period.

Answer №5

To enhance the user experience, consider using JavaScript to redirect upon a successful logout:

window.location.replace("desiredURL");

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using the Unsigned Right Shift Operator in PHP (Similar to Java/JavaScript's >>> Operator)

Before marking this as a duplicate, please take a moment to read the information below and review my code * my updated code! The issue I am facing is that I need to implement Java/JavaScript '>>>' (Unsigned Right Shift / Zero-fill Right Shift) ...

What is the best way to customize the content-type headers for a complete Zend Framework application?

I have come across this question before: Zend Framework how to set headers and I understand how to set headers on a per controller basis. $this->getResponse() ->setHeader('Content-type', 'text/html; charset=utf-8') Howeve ...

Security issue encountered while running imap_getmailboxes in PHP

Having previously written scripts to manage IMAP, such as removing spam emails, I am now working on a more general script to examine available mailboxes. My starting point was the PHP website example for imap_getmailboxes. Here is my adapted version: $use ...

Using Vue.js: Execute a function with a delay, but start the delay over if there is any user input

Imagine a scenario where I have a form that is connected to an API and displays information based on user input. Whenever the user makes changes, such as adjusting the number of results per page, the component should react dynamically by loading new data. ...

Automatically populate fields when the selection changes

Currently, I am facing an issue with a mysql table named clients that I utilize to populate the options of a select in one of the rows. The goal is to automatically fill out 2 input fields with client information when a specific option is selected. To acc ...

javascript / php - modify input fields according to selection change

Can anyone help me with an issue I'm facing? I want to update multiple textfields whenever a new option is selected from my dropdown menu. I've written the following code, but it's not working as expected. Can someone figure out what's ...

Tips for incorporating auth0 into a vue application with typescript

Being a beginner in TypeScript, I've successfully integrated Auth0 with JavaScript thanks to their provided sample code. However, I'm struggling to find any sample applications for using Vue with TypeScript. Any recommendations or resources would ...

How to stop VueJS from exhibiting reactive behavior

Is there a way to utilize VueDraggable to create a cloned item that is completely independent from the original? You can refer to this fiddle for clarification: https://jsfiddle.net/32f7yu7c/69/ In the provided example, dragging an item from one list to ...

Learn how to read the contents of a v-textarea line by line with the help of JavaScript in V

In my v-textarea component, I have set the following properties: <v-textarea v-model="pmidInput" name="input-PMID" ...

Tips for including a hashtag in an AJAX request

When using ajax to send messages to the server in my chat application, I encountered an issue where everything after a hashtag is omitted. I attempted to address this by encoding the message, but it resulted in other complications in the PHP code. The enco ...

Deleting an element from HTML using jQuery

In the midst of creating a system that allows users to construct their own navigation structure, I have encountered a stumbling block. The idea is that when a user lands on the site, they are presented with a list of available topics from which they can ch ...

AJAX responses sans the use of jQuery

Similar Question: How can I achieve this through AJAX? After my previous attempt at asking this question, where I was not clear enough, I am making another effort to be as specific as possible. To start with, I have my data encoded using the json_enc ...

Utilizing Vue and Vuex to execute Axios operations within a store module

Currently, I am developing an application in Vue that utilizes Vuex for state management. For CRUD operations on the data, I have implemented Axios. The issue arises when, for example... I make a POST request to my MongoDB database through an Express ...

Guide to refreshing the webpage content via ajax with Laravel View/Layout approach

Currently utilizing Laravel 4, I am looking to refresh a view and update the content (essentially change the language) Upon arriving at the index page : In my controller : public function getIndex() { $lang = $this->retrieveLang("FR"); ...

Attempting to devise a looping mechanism for implementing WordPress meta boxes by utilizing form field-containing files stored within a designated folder

After developing a method to scan through a directory in search of XML files and then dynamically create WordPress metaboxes for various page and post types, everything seems to be running smoothly. However, an issue arises when attempting to load the file ...

Guide on using axios in vue.js to interact with the API

I need help with a functionality on my website where users can select a car brand from a list of radio buttons. After selecting a brand, I want to retrieve an array of models from the server and display them on a new page. Can someone guide me on what spec ...

Nuxt Axios not connecting with proxy leading to CORS issues

Encountering the following CORS error: Access to XMLHttpRequest at 'https://gw.bilinfo.net/listingapi/api/export' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass acce ...

Find all objects in an array of objects that contain at least one value that matches a given string

I am currently integrating search functionality in my application. The UI search results are generated from an array of objects. My goal is to loop through the name, custNumber, and sneak values in each object and display only the ones that contain a subst ...

Can anyone suggest a more efficient method for looping through this multi-dimensional array in PHP?

I am currently utilizing the Solr search engine, which provides my search results in a structured format: array(2) { ["responseHeader"]=> array(3) { ["status"]=> int(0) ["QTime"]=> int(1) ["params"]=> array(5) { ...

Troubleshooting issue: Displaying input based on selected option not functioning

<custom-select label="Target Type" v-model="targetType" name="targetType" placeholder="Select Target Type" data-test="overall-type-input" :options="targetTypeOptions ...