Introduction

Whenever you start to get serious with a project, you will most likely face the issue of how to handle client-side token-based authentication.

You will have to answer these questions:

How do I store my user’s token?

How do I redirect the user after authentication actions (login/logout)?

How do I prevent route access to authenticated and unauthenticated users?

This article will walk you through these questions and try to illustrate with clear code and good practices in mind.

However, keep in mind that all projects have different authenticated behavior. Projects can be just a loading screen until you are logged in (Gmail), or a view of the application without access to every feature (Amazon), so you will probably have to adjust what I will describe here.

Before we start

I have made this repo if you want to run some code.

We use Vuex as the global state library. Vuex is especially suited for auth management since it’s application-scoped. If you don’t want to use Vuex, no worries — we also give some code example without Vuex 🙂

We also use the axios library for the ajax calls.

Finally, this article will not cover how to implement the backend side of the authentication process. We will only focus on the client side.

Login

Let’s start with a simple login form:

View the code on Gist.

When the user has filled the inputs and clicked Login, we execute the login method.

View the code on Gist.

Here is the first important bit of this code snippet.

Vuex actions returning promises.

this.$store.dispatch(AUTH_REQUEST, { username, password }).then(...)

Did you know? You can also treat action dispatch as promises. Now we can react to successful logins from the component. Allowing us to redirect accordingly.

The same code without Vuex:

View the code on Gist.

Vuex auth module

Let’s now look at this auth module:

First, let’s initialize the state.

We will have the token field (using local storage stored token if present) and a status field, representing the status of the API call ( loading , success or error ).

View the code on Gist.

What about using localStorage and not cookies ?

Well they are actually both good solutions, with their own advantages and disadvantages. This post and this page answer this question pretty well.

Some useful getters:

View the code on Gist.

The ‘isAuthenticated’ getter can seem overkill, however it’s a great way to keep your authentication future proof. By having this getter, you separate data from app logic making it future proof 🙂

Now the action:

View the code on Gist.

And the mutation:

View the code on Gist.

A fairly simple API call from a module. The important bits are:

Token state being initialized by its local storage value, if possible.

The Authentication request action returns a Promise, useful for redirect when a successful login happens.

Good practice: pass the login credentials in the request body, not in the URL. The reason behind it is that servers might log URLs, so you don’t have to worry about credential leaks through logs.

Logout

Since we are at it, let’s implement our logout logic in modules/auth.js:

View the code on Gist.

When clicking on the logout button in one of your components responsible for logout:

View the code on Gist.

In this case, logging out for us means clearing out the user’s token and redirecting them. If you need to perform other Vuex state changes, listen to this AUTH_LOGOUT action and commit.

You can also add a token DELETE request in your action to delete your user token session when logging out.

Try to keep it simple, as few actions as possible to logout/login.

If you start to create one login/logout action per authentication type that you have, you will have a headache maintaining them.

Use the token

Now that we have managed to retrieve the token and store it, let’s use it!

The following example uses Axios and its default headers.

In modules/auth.js

View the code on Gist.

Now after login, all the Axios calls have the authorization header set to your token. All your API calls are authenticated! And when logging out, we delete the authorization header.

Auto-authentication

Right now if we refresh the app, we do have the state correctly set to the previous token. However, the authorization Axios header isn’t set. Let’s fix it!

In your main.js:

View the code on Gist.

Now your API calls are authenticated when refreshing your app after login!

Authenticated routes

Now you probably want to restrict access to your routes depending on whether they are authenticated or not.

In this case, we want only authenticated users to reach /account .

And unauthenticated users should only be able to reach /login and / .

View the code on Gist.

Here we use navigation guards. They allow us to put conditions on routes access that we use to our advantage in conjunction with the Vuex store.

Note 1: If you do not wish to use Vuex, you can still check for token presence in the local storage rather than looking at the store getters 🙂

Note 2: Ed @posva, maintainer of vue-router, also advises the usage of meta attributes, check it out 🙂

Handling the unauthorized case scenario

…but wait, what if the token is expired? What if the user is unauthorized?

No worries here.

Using Axios, you can intercept all responses, and especially the error response. Just check for all unauthorized responses (HTTP 401) and if so, dispatch a logout action.

In your App.vue

View the code on Gist.

And we are good to go!

Conclusion

What have we achieved here?

Isolated authentication logic from the app and other libs.

We won’t need to explicitly pass tokens to every API call.

Handle all unauthenticated API calls

We have auto-authentication

We have restricted routes access

What have we learned?

Separation of concerns

Avoid side effects

Action dispatch can return promises

This should give you a pretty solid starting point for handling all of your API calls in your app.

Hopefully, this will be helpful for your future projects! If you’re interested in learning how to avoid cross-site scripting (XSS) in your Vue.js app check out my previous post. And if you’re interested in protecting your apps at runtime, try Sqreen for free.