Laravel API + Vue SPA Authentication
Most of the times I have heard it’s difficult to Autheticate a Client in Single Page Apps(SPA) using an access token (OAuth 2.0), that’s why today we will see how to implement it.
Let’s get started!
Before I start I want to mention, we will have an API Based in Laravel 5.4 and a Client Based in VueJS. And I will assume you have configured Laravel to deliver access_tokens, as well as the Cross-Origin Resource Sharing (CORS).
If you have not configured that, I recommend you, watch this video by Taylor Otwell.
Maybe, when you try to ask for an access token you may get the next error:
XMLHttpRequest cannot load http://localhost:800/api/users/user.
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8000' is therefore not allowed access.
For this issue, check this tutorial.
Resources & Packages used in this post
- NodeJS 8.4.0
- NPM 5.3.0
- Laravel 5.4
- VueJS 2.4.2
- Quasar-cli (installed globally npm install quasar-cli -g)
- Vue Devtools
Creating Vue Scaffold
To create the scaffold of this project we’ll use Quasar. Quasar is a framework to create web apps, Mobile apps for Android & iOS (Using Cordova) and Electron Apps (Cross Platform Desktop Apps).
Since we have installed quasar-cli we’ll run in terminal
$ quasar init vue-app
Here we are creating a project called vue-app, if everything is okay we should see something like in the image below:
Then, access to the folder vue-app and run npm install. When npm has finished, run: quasar dev.
You should see something like this
Creating bootstrap file
Considering that we have the next structure, we will create a new folder bootstrap, and then a index.js file (src/bootstrap/index.js). In this file all the configurations will be injected.
To inject this plugin in Vue we will go to src/main.js and add:
import Bootstrap from ‘./bootstrap’
To make sure the plugin is working check your console, you should see the text “Bootstrapping”
Note: The log appears 10 times because this plugin is injected in all vue components.
Creating Config oAuth File
When you are developing you may use three environments, local, dev, and production, to switch easier among environments you should create a file where the oauth credentials will be stored
Creating OAuth Class
Now, we create a new file in a new folder: oauth/index.js
If we pay attention in each method of the previous class, we can see methods to Login, get current user (getUser), check if there is an active session(isAutheticated) as well as a logout.
The good part is you can use instantiate this class in any file in our app, to login or. However, if we want to use it in a Vue component I think it’s better to create a helper, let me show you what I am talking about:
so, in this way we can use it in every component through this.$oauth
OAuth Service file
If we check the line 9 of oauth/index.js file we have imported a service, this file is used to make the requests to our server.
Basically, we have an Auth Class which has Service to make requests as well as a file where our http routes are stored.
With these last changes we can implement a component Login.vue to authenticate a user:
And then, create a new route for this view:
After you have created this file you may get a npm error, saying sass-loader does not exist, please, just run :
npm install sass-loader node-sass — save-dev
Then, we should see this:
API GrantType Credentials
Do you remember the file src/config/auth.js? Well, in this file we’ll add the client_id, client_secret as well as the grant type. In this case, since we are working in local, we should set API_LOCAL property
Authenticating a user
we will focus in the segment of code:
In this code we attempt to log in, in case the login is successfully we’ll be redirected to ‘/’, otherwise a toast with ‘Email or Password incorrect’ will be rendered.
And that’s it!!! If we have logged in correctly and we want to make sure our access token is stored we can check in google chrome console. You can use LocalStorage or Cookies, personally I like Cookies, however, if you are planning to wrap your app in Android or iOS, you must use LocalStorage.
Remember if you need to swich between these two you can change it in
src/config/auth.js > default_storage
Solving the error 401 Unauthorized
Now that we have logged in successfully, and we want to get the current user we are getting this error:
The reason is we are not sending the Authorization header in each request, to achieve that we will create a new folder interceptors and then a file axios.js
Finally , we need to inject it in our bootstrap file src/bootstrap/index.js
If we refresh, and try again, we should be able to see the current user:
If we want to log out, the result will be in the following example. Supposing we are in the main view (for this example Hello.vue).
To logout successfully, we are using our $oauth helper, and taking advantage of this class we are also getting the current user. This view would be something like this:
Protecting your routes
I am very sure you will need to protect some views from unregistered users, one thing very important for our application, to achieve that, we are creating another interceptor provided by vue-router, but firstly we are adding a new property (meta) in the route that you want to protect.
Then, we create a new file in src/interceptors/v-router.js
And finally, we import it in our bootstrap file:
And that’s it! Now, when you want to access to http://localhost:8080/#/ and you are not logged, you will be redirected to http://localhost:8080/#/login.
Perhaps, the flow that we did is kinda messy, but when you want to change a setting it will be easy to change. for example:
- To decide between LocalStorage or Cookies used to store our access_token.
- To change easily the environments local, dev, production.
- Handle the interceptors easily, where we can transform our requests, or check if one specific route must be displayed only for authenticated users.