Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

alexhackney's avatar

How to securely store sanctum token

I'm moving most of frontend app to vue 3 and instead of doing a spa, I'm was just going to have vue apps for each part of the site. I'm also using pinia to manage state.

I have a UserStore that handles the user data and authentication stuff that I need.

I'm using sanctum to manage authentication of requests and I have log in working fine, but as part of the process I return the sanctum token in plaintext for the app to use on subsequent requests.

The issue I'm running in to though is how do I persist the token across page reloads?

I could either store it in the local storage for the browser but I feel like that's kind of insecure. Am I wrong?

I think another option could be to store the token in the user session then just make it available on every page but I'm not clear on how to make that happen securely?

There are a lot of articles on spas and how to do it there. It makes sense in that context because the page never really refreshes, but if I'm not doing an spa, I need to store that data somewhere.

0 likes
5 replies
LaryAI's avatar
Level 58

Storing the token in local storage is not the most secure option as it can be vulnerable to cross-site scripting attacks. A better option would be to store the token in an HTTP-only cookie, which cannot be accessed by JavaScript and is therefore more secure.

To do this, you can modify the Laravel Sanctum configuration to use cookies instead of the default token-based authentication. In your config/sanctum.php file, set the stateful option to true and the driver option to cookie:

'stateful' => true,
'driver' => 'cookie',

Then, in your Vue app, you can use the axios library to send requests with the withCredentials option set to true, which will include the cookie in the request:

axios.get('/api/user', { withCredentials: true })

Finally, to make sure the cookie is secure, you should set the secure option to true in your config/session.php file, which will ensure that the cookie is only sent over HTTPS:

'secure' => true,

With these changes, your Sanctum token will be stored securely in an HTTP-only cookie and will be sent with every request, even after a page reload.

1 like
roselykm's avatar

@LaryAI When I test my Laravel API in Postman, Sanctum is using Bearer token for API authorization. Is this withCredentials: true also emulate Bearer Token authorization?

CamKem's avatar

You could use axios to get the sanctum token & just store it in a cookie. Then check to see if there is a sanctum token stored in each different vue app & store it in the Pinia store. Or you could make an axios request for the token in each new vue app & store it in the pinia store. Either way, you will need to have the same logic check/get token & then log the user in through each vue app (as far as I know how)

    axios.defaults.withCredentials = true;
    const response = axios.get(apiUrl('sanctum/csrf-cookie','backend-non-api-route')).then(response => {
        return axios.post(apiUrl('user/login','backend-non-api-route'),data,{ 
            xsrfHeaderName: "X-XSRF-TOKEN", 
            withCredentials: true
          });
    })
    return response;
CamKem's avatar

You could also nest your vue apps inside of a parent app & have the parent app handle navigation & authentication, then the nested app just do what they need to do.

<div id="parent">
    <div id="child1" v-pre>
    </div>
    <div id="child2" v-pre>
    </div>

</div>
——
new Vue({
    el: '#parent',
})

new Vue({
    el: '#child1',
})

new Vue({
    el: '#child2',
})
martinbean's avatar

@alexhackney The situation you describe is literally why Sanctum was created.

The Sanctum docs has a section for SPA authentication (https://laravel.com/docs/sanctum#spa-authentication). You should be using cookie-based authentication in your SPA, not tokens, as then you don’t have to worry about plaintext tokens being transmitted client-side or stored insecurely in client-side storage such as localStorage.

Please or to participate in this conversation.