Laravel JWT Auth with Vue.js

Vue Resource

Before moving on to the API code, the registration form needs to be setup to post the data. The Vue.js resource plugin provides services for making web requests and handling responses. Install the resource plugin for Vue.js

npm install vue-resource --save-dev

Update resources/js/app.js to require the vue-resource plugin after vue and the vue-router. Also add the Vue.http.headers and Vue.http.options.root url. Laravel VerifyCsrfToken middleware will check for the X-CSRF-TOKEN request header. To make this token available to the client side script, it is being stored in a meta tag via resources/views/welcome.blade.php. The Authorization header is needed for JWT auth which will be added with the sign-in form later.

app.js
var Vue = require('vue');
var VueRouter = require('vue-router');
var VueResource = require('vue-resource');

Vue.http.headers.common['X-CSRF-TOKEN'] = document.getElementsByName('csrf-token')[0].getAttribute('content');
Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token');
Vue.http.options.root = 'http://laravel.dev:8080';

...

Create a resources/js/auth.js JavaScript file.

touch resources/assets/js/auth.js

Add the following code to auth.js to handle the API request when the register form is submitted.

auth.js
import Vue from './app.js';
import {router} from './app.js';

export default {
    user: {
        authenticated: false,
        profile: null
    },
    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
        })
    }
}

Add the following script to the bottom of the Register.vue file to handle the register form submit.

Register.vue
...

</template>

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

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

Run gulp then fill out and submit the new user registration form. You should get a error message since the api/register route and respective endpoint has not yet been created.

Laravel JWT Auth Vuejs User Registration Form Error
New User Registration Form Error

API

For form validation, create a FormRequest class. Use the command line and the php artisan make command to generate the class as follows.

php artisan make:request RegisterFormRequest

Edit app/Http/Requests/RegisterFormRequest.php. First, return true instead of false in the authorize function since using JWT for that. Then add the validation rules in the array that is returned in the rules function for the new User as follows.

RegisterFormRequest.php
public function authorize()
{
    return true;
}

...

public function rules()
{
    return [
        'name' => 'required',
        'email' => 'required|email|unique:users',
        'password' => 'required',
    ];
}

Edit the pre-existing app/Http/Controllers/Auth/AuthController.php. Replace everything below the namespace declaration with this code.

AuthController.php
...

use App\Models\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\RegisterFormRequest;
use Illuminate\Http\Request;

class AuthController extends Controller
{
    public function register(RegisterFormRequest $request)
    {
        User::create([
            'name' => $request->json('name'),
            'email' => $request->json('email'),
            'password' => bcrypt($request->json('password')),
        ]);
    }
}

Test the form and API by registering a new user. The users table of the database should contain a new user record. Try registering another user with the same e-mail address to test the validation.

JWT Auth

For Laravel JSON web token authentication, install jwt-auth using composer require.

composer require tymon/jwt-auth

Edit config\app.php adding the service JWTAuthServiceProvider to the providers array and under the aliases array, add the JWTAuth facade.

app.php
...

'providers' => [
    ...

    Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
]

...

'aliases' => [
    ...

    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
]

Publish the configuration.

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

Generate a key in the published configuration.

php artisan jwt:generate

Edit the published configration config\jwt.php file by updating 'user' => 'App\User' since the User model namespace has been changed from the default.

jwt.php
...

'user' => App\Models\User::class,

User Endpoint

Create the User controller.

php artisan make:controller UserController

Edit the app\Http\Controllers\UserController.php adding the index method to return the user data.

UserController.php
...

use Illuminate\Http\Request;

use App\Http\Requests;

class UserController extends Controller
{
    public function index(Request $request)
    {
        $data = [];
        $data['name'] = $request->user()->name;
        $data['email'] = $request->user()->email;
        return response()->json([
            'data' => $data,
        ]);
    }
}

Add the signin method to the AuthController class and update the use statements for the external classes as follows.

AuthController.php
...

use App\Models\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\RegisterFormRequest;
use Carbon\Carbon;
use JWTAuth;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;

class AuthController extends Controller
{
    public function register(RegisterFormRequest $request)
    {
        User::create([
            'name' => $request->json('name'),
            'email' => $request->json('email'),
            'password' => bcrypt($request->json('password')),
        ]);
    }

    public function signin(Request $request)
    {
        try {
            $token = JWTAuth::attempt($request->only('email', 'password'), [
                'exp' => Carbon::now()->addWeek()->timestamp,
            ]);
        } catch (JWTException $e) {
            return response()->json([
                'error' => 'Could not authenticate',
            ], 500);
        }

        if (!$token) {
            return response()->json([
                'error' => 'Could not authenticate',
            ], 401);
        } else {
            $data = [];
            $meta = [];

            $data['name'] = $request->user()->name;
            $meta['token'] = $token;

            return response()->json([
                'data' => $data,
                'meta' => $meta
            ]);
        }
    }
}

Edit app\Http\Kernel.php adding jwt.auth to the application’s route middleware array.

kernel.php
...

protected $routeMiddleware = [
    ...

    'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
];

Edit app\Http\routes.php adding the signin and jwt.auth route group to authorize access to the user endpoint.

routes.php
...

Route::group(['middleware' => ['api']], function () {
    Route::post('/api/register', [
        'uses' => 'Auth\AuthController@register',
    ]);

    Route::post('/api/signin', [
        'uses' => 'Auth\AuthController@signin',
    ]);

    Route::group(['middleware' => 'jwt.auth'], function () {
        Route::get('/user', [
            'uses' => 'UserController@index',
        ]);
    });

});

The last page covers the remainder of the front end code including sign in, sign out and navigation component updates.


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 ...