Laravel JWT Auth with Vue.js 2

Sign in Form

Add the following code to the Signin.vue file.

Signin.vue
<template>
    <div>
        <div class="alert alert-danger" v-if="error">
            <p>There was an error, unable to sign in with those credentials.</p>
        </div>
        <form autocomplete="off" v-on:submit="signin">
            <div class="form-group">
                <label for="email">E-mail</label>
                <input type="email" id="email" class="form-control" placeholder="gavin.belson@hooli.com" v-model="email" required>
            </div>
            <div class="form-group">
                <label for="password">Password</label>
                <input type="password" id="password" class="form-control" v-model="password" required>
            </div>
            <button type="submit" class="btn btn-default">Sign in</button>
        </form>
    </div>
</template>
<script>
import auth from '../js/auth.js';

export default {
    data() {
            return {
                email: null,
                password: null,
                error: false
            }
        },
        methods: {
            signin(event) {
                event.preventDefault()
                auth.signin(this, this.email, this.password)
            }
        }
}
</script>

Dashboard

Add the following code to the Dashboard.vue file. This template populates the router-view element in the base layout component when the user is authenticated.

Dashboard.vue
<template>
    <h1>Laravel 5 - Dashboard</h1>
</template>

Update auth.js to handle all of the authorization functions.

Note the changes between version 1.0 of auth.js. For consistency with the HTML5 history API, router.go is now only used for back/forward navigation. Therefore, router.push replaces router.go in this use case.

auth.js
...

export default {
    user: {
        authenticated: false,
        profile: null
    },
    check() {
        let token = localStorage.getItem('id_token')
        if (token !== null) {
            Vue.http.get(
                'api/user?token=' + token,
            ).then(response => {
                this.user.authenticated = true
                this.user.profile = response.data.data
            })
        }
    },
    register(context, name, email, password) {
        Vue.http.post(
            'api/register',
            {
                name: name,
                email: email,
                password: password
            }
        ).then(response => {
            context.success = true
        }, response => {
            context.response = response.data
            context.error = true
        })
    },
    signin(context, email, password) {
        Vue.http.post(
            'api/signin',
            {
                email: email,
                password: password
            }
        ).then(response => {
            context.error = false
            localStorage.setItem('id_token', response.data.meta.token)
            Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token')

            this.user.authenticated = true
            this.user.profile = response.data.data

            router.push({
                name: 'dashboard'
            })
        }, response => {
            context.error = true
        })
    },
    signout() {
        localStorage.removeItem('id_token')
        this.user.authenticated = false
        this.user.profile = null

        router.push({
            name: 'home'
        })
    }
}

Update the VueRouter routes array in app.js to include the Dashboard and Signin components.

app.js
...

export var router = new VueRouter({
    routes: [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard
        },
        {
            path: '/register',
            name: 'register',
            component: Register
        },
        {
            path: '/signin',
            name: 'signin',
            component: Signin
        }
    ]
});

...

Finishing Touches

1. Update the App.vue navigation inside the nav so the Register link is only available when applicable. Add a Sign in and Sign out link along with a list item to show the users name when signed in.

2. At the bottom of the App.vue file add a script to bind the auth.js methods.

Note the ready function in version 1.0 of App.vue has been replaced with the mounted hook.

App.vue
...

<nav>
    <ul class="list-inline">
        <li>
            <router-link :to="{ name: 'home' }">Home</router-link>
        </li>
        <li class="pull-right" v-if="!auth.user.authenticated">
            <router-link :to="{ name: 'register' }">Register</router-link>
        </li>
        <li class="pull-right" v-if="!auth.user.authenticated">
            <router-link :to="{ name: 'signin' }">Sign in</router-link>
        </li>
        <li class="pull-right" v-if="auth.user.authenticated">
            <a href="javascript:void(0)" v-on:click="signout">Sign out</a>
        </li>
        <li class="pull-right" v-if="auth.user.authenticated">
            Hi, {{ auth.user.profile.name }}
        </li>
    </ul>
</nav>

...

<script>
import auth from '../js/auth.js'

export default {
    data() {
            return {
                auth: auth
            }
        },
        methods: {
            signout() {
                auth.signout()
            }
        },
        mounted: function () {
            this.$nextTick(function () {
                auth.check()
            })
        }
}
</script>

Run the npm build script and give it a test drive.

npm run build

Used in this build:

  • Laravel 5.2
  • JWT Auth v0.5.9
  • Vue v2.1.1
  • Vue-cli v2.8.1
  • Vue-resource v1.2.0
  • Vue-router v2.1.1
  • Webpack v2.2.0
Source Code

Published by

Jim Frenette

Web Developer - views here are my own except those taken from people more clever than me.

Loading Disqus Comments ...
Loading Facebook Comments ...