Session cookies between Express.js and Vue.js with Axios

Tamás Polgár
Developer rants
Published in
3 min readAug 17, 2020

It seems to be more difficult to make Axios play nice with the backend than it should be.

In my recent post I wrote about building Google authentication for a Vue.js and Node.js/Express project. My closing words were: “It’s a good idea to start a session and save the user’s name, user ID and perhaps email address for further reference.” I got some feedback from readers and it seems that implementing this is harder than it sounds. Axios, the HTTP library most frequently used for Vue.js doesn’t take or send cookies automatically, including the session ID, and Express also doesn’t send them just like that. So even if you set session variables in Node, the frontend will remain ignorant of them, and the user will be treated as not signed in, since no session identification is arriving to the backend.

The backend side

Implementing sessions in Node and Express is fairly easy. You’ll need a few dependencies:

npm i cookie-parser express-session cors

Let’s import them…

import * as cookieParser from 'cookie-parser';
import * as session from 'express-session';
import * as cors from 'cors';

Now let’s set up session and cookie handling.

//  Populate req.cookies
this.express.use(cookieParser());
// Session setup
this.express.use(session({
secret: 'wow very secret',
cookie: {
maxAge: 600000,
secure: true
},
saveUninitialized: false,
resave: false,
unset: 'destroy'
}));

What does this all mean? The session setup has the following parameters:

secret is a random string, a key to encode session cookies. It’s a required option.

cookie.maxAge sets how long a cookie should stay alive, in milliseconds. In this example it’s 10 minutes.

cookie.secure tells Express to use secure cookies or not. If true, the Set-Cookie: Secure value will be added to response headers. Here’s the catch: it only works with HTTPS. Plain old HTTP doesn’t support secure cookies, and the entire session handling simply won’t work if you set it to true. So if you’re not using HTTPS, set it to false. Sessions will still work, only the cookie won’t be a secure one.

saveUninitialized tells Express to save a new session if it doesn’t exist yet. This is recommended to be set to false when implementing login sessions. The default value is true, but this is going to change in future versions of express-session.

resave is another required option. When true, the session will be saved at every single call made by the client, regardless if it’s been changed or not. Typically it should be false. Just like with saveUninitialized, the default value is true which is going to change.

unset tells Express what to do with the session when the client ends it. I usually set it to destroy which deletes all session data. The other option is keep but why would you want to hold on to expired data?

For more information see the documentation of express-session.

Now we also have to set up CORS policies.

this.express.use(cors({
origin: [
'http://localhost:8080',
'https://localhost:8080'
],
credentials: true,
exposedHeaders: ['set-cookie']
}));

CORS regulates what domains can make a call to your backend, and it’s essential to prevent cross-site attacks. Here I allowed localhost:8080 because this is what I use for development. In a production environment you should add your domain name and IP address in a similar fashion, preferably both with https:// and http://.

What matters here is the credentials setting. It orders Express to pass a header along with all HTTP responses. As cookies travel with the header, and the session cookie is one of them, obviously we need this to be true.

exposedHeaders is a list of header fields to be included in the header. We’re only interested in cookies, so that’s the only option here.

For more options see the Express CORS documentation.

The frontend side

Telling Axios to accept session cookies is a breeze now. Open your main.ts file and…

import axios from 'axios';
import VueAxios from 'vue-axios';
axios.defaults.withCredentials = true;
Vue.use(VueAxios, axios);

This will automatically add withCredentials: true to every single HTTP request made by Axios. If you wish to override it:

Vue.axios.post(
'http://my.server.com/',
{
data: 'some post data'
},
{
withCredentials: false
})

Now your frontend and backend will finally play together nicely, and your backend will recognize the client every single time it connects.

How to destroy the session?

req.session.destroy();

That’s how you sign out a client. If you’re using a third party authentication service like Firebase Authenticate on the client side, don’t forget to call it too to sign out.

--

--