Vue.js ❤️ Craft CMS - Single Page App: Logging in to Craft

Today I'm going to focus on logging into Craft from the frontend of the site. Of course, this isn't always necessary for every circumstance but if you're building a single page app, it's more than likely this will be functionality that you need.

I want to add my authorisation layer into the view that allows a registered user to post a new entry which is New.vue

I'm going to scaffold my logic within the Vue template first before actually hooking it up with the Vue instance itself.

Firstly, I need to give a hat tip to Selvin Ortiz for pointing out the issues with using Axios to post data. This tripped me up at first.

I'll display my post form conditionally using Vue's v-if directive. If that v-if is false, then I'll use the v-else directive to display my login form. My first check is simply this

Then I'll add my v-else to display the login form

This is pretty much your standard Craft login form but with a couple of differences. I want to prevent the default action on a form (which would result in a page refresh) by using @submit.prevent however, I want to run a Vue method when my form is submitted. So that becomes @submit.prevent="doLogin" and we'll dive into the method further.

I then have another v-if directive for erroring which will be dependent on the response I get from the server.

When I first tried to hook this up, I was running into the issue where I'd get this response The CSRF token could not be verified. So I had to make an addition to my layout _layouts/_master.twig

I'm adding the Craft csrfTokenName and the csrfTokenValue via JS and I can grab those as computed properties in a Vue component.

Next I have the standard Craft username and password fields but rather than set the values to an empty string, I've bound them using the v-model directive and bound them to properties of an object theUser. The v-model directive will then keep the data in either of these fields reactive to the Vue instance.

Making the template functional

Here's the entirety of my script tag in this component and I'll take it line by line to explain what's going on.

First off, for the reasons stated in Selvin's Stackexchange answer, I'm going to use Vue Resource rather than Axios to post my data to Craft. To add that npm install vue-resource --save and then I can import it on line 1 like above.

The name of the component is standard and should be familiar at this point.

Next I'm setting loggedIn as an available prop.

After that, we start getting a little more involved.

I have a theUser object which sets the default properties of the user. By default, my username and password are null my action is the default Craft method for user login and my return url takes them to the current page but this time loggedIn should now be true and the entry form will be in place.

I then have errors and message set to null and I'll populate these in my methods if they're needed.

My computed properties csrfName and csrfToken are set by grabbing what's been set from the JS in my Twig template.

The actual login

The doLogin method is the key here to communicating with Craft.

The first thing I'm doing is creating an alias of my user object by setting it to let data = this.theUser. That data is then being posted to Craft. If the response body is successful, then Vue Router is used to redirect the user to /new but as an authenticated user. If the response receieved errors then I'm setting my errors to be the same as what the server returns and those will display based on the logic of the v-if="errors" directive.

All things being well, you should now be able to fail a test login that will highlight errors and also login successfully.

I've also made the source code available on GitHub if you'd like to grab that in addition to the Gists.

As always, comments are open for erratum