Laravel JWT Authentication – Vue Js SPA (Part 1)

3 1,987

In this article, we will discuss the Laravel JWT Authentication – Vue Js SPA. As you know, we already discuss the same in our previous article. But, we are creating this tutorial with some new amendments. So I’m creating this in the separate setup with latest versions of Laravel and JWT.

I’m considering this you already know Laravel, if you are still not familiar with this, then go and take a look at the Laravel Documentation or my other article on Laravel for more understanding.

Laravel Application Setup

Use the following composer command to create your application.

composer create-project laravel/laravel laravel_jwt_vuejs --prefer-dist

Add JWT Auth Package

You can use the composer command to add a package in your application. It is one of the easy ways to add any package into the Laravel application.

composer require tymon/jwt-auth:dev-develop // "dev-develop" means still under development

Publish JWT Configuration

Here, we can use an artisan command to publish the JWT package configuration.

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

// You can also use this command without provider flag, and select provider from the given list.

After executing the above mention command, this will create the configuration at “config/jwt.php”.

Create JWT Secret

You can create the JWT secret using the following artisan command.

php artisan jwt:secret

This command creates a secret code for JWT internal use. You can find this in your “.env” file.

Update Auth Config

Open your “config/auth.php” then update the default guard and API driver.

// Default Guard
'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

// Driver of the API Guard
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

Because I’m creating a new directory “Models” for storing all my models. So need to update the provider model for the users.

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
],

Update User Model

Open user model, it’s provided with the Laravel application. As I already mention about the changes of the custom Model directory, You need to update the following code into your model file.

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'role'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
    
    public function getJWTCustomClaims()
    {
        return [];
    }
}

Don’t forget to add getJWTIdentifier() and getJWTCustomClaims() methods that are required by the JWT interface.

Update Authentication Middleware

Here, I’m updating my “app/Http/Middleware/Authenticate.php” middleware. I’m overriding the handle and authenticate method and I’m setting out to return the JSON formatted responses. Because this setup will be used in Vue Js application where I need JSON formatted responses and login page will be handled by the Vue Js.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    // Override handle method
    public function handle($request, Closure $next, ...$guards)
    {
        if ($this->authenticate($request, $guards) === 'authentication_failed') {
            return response()->json(['error'=>'Unauthorized'],400);
        }
        return $next($request);
    }

    // Override authentication method
    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }
        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }
        return 'authentication_failed';
    }
}

You have seen the “Route [login] not defined” error when you try to access “http://127.0.0.1:9090/api/v1/user/1” URL. So I’m applying changes in our middleware as mentioned above. After applying those changes when we access the same URL then we receive the error in JSON format.

Laravel JWT Auth - VueJs

Laravel JWT Auth - VueJs

Laravel Routes

Now, we will create required authentication routes in the “routes/api.php”. You just need to add the following routes:

Route::prefix('v1')->group(function () {
    Route::prefix('auth')->group(function () {

        // Below mention routes are public, user can access those without any restriction.
        // Create New User
        Route::post('register', 'AuthController@register');

        // Login User
        Route::post('login', 'AuthController@login');
        
        // Refresh the JWT Token
        Route::get('refresh', 'AuthController@refresh');
        
        // Below mention routes are available only for the authenticated users.
        Route::middleware('auth:api')->group(function () {
            // Get user info
            Route::get('user', 'AuthController@user');

            // Logout user from application
            Route::post('logout', 'AuthController@logout');
        });
    });
});

Create Auth Controller

php artisan make:controller AuthController

This will create an “AuthController.php” controller at “app/Http/Controllers”.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Auth;
use Validator;
use App\Models\User;

class AuthController extends Controller
{
    /**
     * Register a new user
     */
    public function register(Request $request)
    {
        $v = Validator::make($request->all(), [
            'name' => 'required|min:3',
            'email' => 'required|email|unique:users',
            'password'  => 'required|min:3|confirmed',
        ]);
        if ($v->fails())
        {
            return response()->json([
                'status' => 'error',
                'errors' => $v->errors()
            ], 422);
        }
        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        return response()->json(['status' => 'success'], 200);
    }

    /**
     * Login user and return a token
     */
    public function login(Request $request)
    {
        $credentials = $request->only('email', 'password');
        if ($token = $this->guard()->attempt($credentials)) {
            return response()->json(['status' => 'success'], 200)->header('Authorization', $token);
        }
        return response()->json(['error' => 'login_error'], 401);
    }

    /**
     * Logout User
     */
    public function logout()
    {
        $this->guard()->logout();
        return response()->json([
            'status' => 'success',
            'msg' => 'Logged out Successfully.'
        ], 200);
    }

    /**
     * Get authenticated user
     */
    public function user(Request $request)
    {
        $user = User::find(Auth::user()->id);
        return response()->json([
            'status' => 'success',
            'data' => $user
        ]);
    }

    /**
     * Refresh JWT token
     */
    public function refresh()
    {
        if ($token = $this->guard()->refresh()) {
            return response()
                ->json(['status' => 'successs'], 200)
                ->header('Authorization', $token);
        }
        return response()->json(['error' => 'refresh_token_error'], 401);
    }

    /**
     * Return auth guard
     */
    private function guard()
    {
        return Auth::guard();
    }
}

In this controller, I’m applying the simple logic to make the registration and login process.

The register() method create a new user after validation.

The login() method use the Auth::guard() method that use the JWT. The attempt() method checks the given credentials then after the success, it will generate a token which will be returned in the headers of the response.

The refresh() method regenerate a token if the current token is expired. You can manage the duration in the “config/jwt.php”. And reset the duration as per your application requirement. You just need to add JWT_TTL in your “.env” file. By default, the JWT token is valid for 60 minutes (1 Hour).

JWT_TTL=10

I’m changing this limit to 10 minutes, from now our JWT token is valid only for the 10 minutes.

The “logout()” method simply unset the token.

The “user()” method returns the authenticated user details.

You can test those API in postman.

Laravel JWT Vue js

Laravel JWT Vue Js

Conclusion

In this article, We are discussing Laravel JWT Authentication for our Vue Js application. This is the first part of this series. In the next tutorial, we will cover the Vue Js setup and connect this API with Vue Js application. You can get the Github repository link in the 2 part of this series Please feel free to add your comments if any query. You can also send me your feedback 😉

Leave A Reply

Your email address will not be published.

3 Comments
  1. Ilnar says

    Hey, there! That is not work on 2019.04.15. After “Update Authentication Middleware” I do not see “Route [login] not defined”, i am seen “404 Not Found” that is matter? Where is error? How can i decide this?

    1. Code Briefly says

      It’s hard to reproduce the same. Please check at your end each of the step you follow. You can also go with the Github repository.

      1. Ilnar says

        Thx a lot. I did it! Next lesson is communicatw jwt back-end with vuejs!