Posted by Arjun on Sunday 11th February 2018

Laravel 5.6 - REST API - JWT Authentication

Laravel 5.x Laravel 5.6 laravel-jwt jwt refresh

In my last tutorial, we created an APIs for todo application without authentication. In this tutorial, I would like to show you building JWT based login system. Let's start...

Create Project

Create a brand new Laravel 5.6 project with Composer create-project command:

$ composer create-project laravel/laravel arjunphp-jwt-auth 5.6 --prefer-dist

Database connection settings

After creating project open .env file and update your database credentials:

...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=arjunphp_jwt_auth
DB_USERNAME=root
DB_PASSWORD=mysql
...

Next step, would be, go to the project root and open the terminal and type the following command. It will create the two tables, which is by default ships by Laravel 5.6

$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

You might get following error :

 PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes")

to fix this, all you have to do is to edit your AppServiceProvider.php file and add to the boot method a default string length:

...
use Illuminate\Support\Facades\Schema;

....
function boot()
{
    Schema::defaultStringLength(191);
}
...

We gonna use jwt-auth library to generate and handle the JWT tokens, so let got to root of the project and run following Composer command from your terminal:

composer require tymon/jwt-auth

Then add the service JWTAuthServceProvider to the providers' array and the JWTAuth facade to the aliases array in config/app.php

...
'providers' => [
    ...
    Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
]
...
'aliases' => [
    ...
    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
]

Now publish the configuration file

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

Now generate a key in the published configuration

php artisan jwt:generate

Note: if this error gives you an error checkout below link to fix it.
https://github.com/tymondesigns/jwt-auth/issues/1298

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

protected $routeMiddleware = [
    ...
    'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
    'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];

Now let's create the AuthController by issuing below command from the root of your project:

$ php artisan make:controller AuthController
Controller created successfully.

Going forward we gonna define register, login, logout, refresh and user methods in the AuthController.

signup

Let register a signup route.

Route::post('signup', '[email protected]');

Let us also create a FormRequest to handle validation for every registration request.

php artisan make:request RegisterFormRequest

Now edit our RegisterFormRequest class to reflect the code below.

class RegisterFormRequest extends FormRequest
{
    public function authorize()
    {
         return true;
    }
    public function rules()
    {
        return [
            'name' => 'required|string|unique:users',
            'email' => 'required|email|unique:users',
            'password' => 'required|string|min:6|max:10',
        ];
    }
}

Final setup, create the register method that will handle user registrations

public function register(RegisterFormRequest $request)
{
    $user = new User;
    $user->email = $request->email;
    $user->name = $request->name;
    $user->password = bcrypt($request->password);
    $user->save();
    return response([
        'status' => 'success',
        'data' => $user
       ], 200);
 }

Login

Let's deinfe login route

Route::post('login', '[email protected]');

Create the login method in AuthController, it will handle the user logins

public function login(Request $request)
{
    $credentials = $request->only('email', 'password');
    if ( ! $token = JWTAuth::attempt($credentials)) {
            return response([
                'status' => 'error',
                'error' => 'invalid.credentials',
                'msg' => 'Invalid Credentials.'
            ], 400);
    }
    return response([
            'status' => 'success',
            'token' => $token
        ]);
}

Current User

Let us define user route, it will give you current user information

Route::group(['middleware' => 'jwt.auth'], function(){
  Route::get('auth/user', '[email protected]');
});

Define user method in controller, which will return current user information

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

Logout

Now define logout route in routes/api.php.

Route::group(['middleware' => 'jwt.auth'], function(){
   Route::post('auth/logout', '[email protected]');
});

Here is the log-out method which will handle the logout requests.

public function logout()
{
    JWTAuth::invalidate();
    return response([
            'status' => 'success',
            'msg' => 'Logged out Successfully.'
        ], 200);
}

Refresh token

Define route to check the current token is valid or not and refresh the token if it is not invalidated.

Route::middleware('jwt.refresh')->get('/token/refresh', '[email protected]');

create refresh method with below code

    public function refresh()
    {
        return response([
         'status' => 'success'
        ]);
    }