Users authentication with Vue.js & Lumen

Users authentication is an important part of many web apps. In this post I would like to show you how to create simple authorization with Vue.js, Lumen and JSON Web Tokens.

JSON Web Tokens (JWT)

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA more on jwt.io.

How will our user authentication works? We’ll send our user email and password to API (Lumen) and if they are correct, we’ll get a unique token. We’ll save it in LocalStorage and next we will send it with request to secured parts of our App.

Prepare Lumen

For JWT in our backend we’ll use tymon/jwt-auth. A great tutorial you can find on Wade Urry’s blog, so I won’t copy it. The how-to is for Lumen 5.2 but I tested it with 5.4 version and it works fine.

By default we get only a token but if we want to show some info about the user (for example name & avatar in the app header or any hello message) we can get it immediately with the token. So I made a small modification in AuthController@login method:

Now we get the token and authorized user data (in my case they are, among others, first name, last name and e-mail):


Vue Login component

In this part we’ll create Vue Login component and use Vuex for management of an auth state. I’ll skip the most of CSS section because it’s not important here.

Template

First create <template> with <form>:

In the snippet you can see some important elements:

  • form with submit action – login() method;
  • information about login error visible if infoError is true (by default it’s false);
  • div with is-waiting class if loader is true – it’s responsible for displaying a spinner;
  • input (for e-mail and password) with v-model directive – we use it to collect our inputs values;
  • in input I also use trim modifier to automatically remove spaces at the begining or at the end of the string.
Error message when infoError is true

CSS/SCSS – loader/spinner

As I reported, I skipe most of CSS/SCSS code but I would like to show you how I made a loader.

I can add is-waiting class to any HTML element and then I block it and show the loader.

As you can see every child in is-waiting element has lower opacity.

:before pseudo-element is very important – it is 100% size of its parent and higher z-index so in our case I block by them the login form against additional clicks or value changing.

And :after is our real spinner – horizontally and vertically centered in is-waiting element with rotary SVG background image. The source is here.

Spinner added by .is-waiting class (when loader is true)

Script section

OK, here is our JavaScript code:

First we import router (we use it to redirect a logged in user) and store (more about Vuex in a moment).

In data () we define all properties we need – including email and password of course.

beforeCreate () – here we check (using Vuex state) if the user is logged in. If yes – we don’t need to show them the login window and we can redirect them to the right place (home, dashboard etc.).

In our Login component we have only one method – login (). It is responsible for connection to API (I use vue-resource) and authorization attempt. Here we also activate/deactivate the loader and – if it’s needed – we show a login error.

If API returns the token, we save it in localStorage, store (by Vuex store.commit method) that the user is logged in and redirect them by router.


Vuex – state manager

In our app we will certainly check if the user is logged-in in many places. So we need easy to use, centralized state management for all our components – Vuex.

In src catalog create store/index.js file:

At the beginning of the code we create one boolean stateisLogged. We also check if there is a token stored in localStorage and set the initial true or false value.

We alse need mutations LOGIN_USER & LOGOUT_USER – we will use them to change the isLogged state from different places of our application.

Finally we also turn on a strict mode for non-production environments. More about this you can find in Vuex documentation.

Now we can check in any place/component of our app if the user is logged in. If they aren’t, we can redirect them automaticaly to a Login component:


Router – login & logout

Of course, we need to create the router for our Login component but the app should also give our user possibility to log out.

Your router/index.js file should be similar to this snippet:

So if we have /logout path, let’s add a Logout component.


Logout component

Our Logout component is extremally simple:

All we need when the user opens this url is:

  • remove token from localStorage,
  • change isLogged state in Vuex by committing LOGOUT_USER mutation,
  • and finally, we can redirect our user to /login path and show them a login form.

At this point, we have everything we need to authorize users and give them (or not) secure API data. So let’s see how to authorize secured request when the user is logged in.

Request authorization

To protect our routes on the server side we can use Laravel/Lumen auth middleware. More here.

As an example I created /secured endpoint.

If the user is successfully authorized, they receive a hello message in the API response. Otherwise they get 401 error with “Unauthorized” message.

OK, let’s try it with Vue:

As you can see, we need to add Authorization header to our request and provide the token obtained at the login stage. If everything is done correctly, you should see in the browser console:

message: 'Hello!'

I hope you’ll find this tutorial helpful. If you have any questions or any objections to the content, feel free to leave a comment! If you like it – click the heart!