Loading

Creating a JWT Authenticated REST API with Lumen

Creating a JWT Authenticated REST API with Lumen

In the previous article, I have written a step by step guide about how to build a REST API with a lumen in this article I will use that blog application to validated with JWT authentication. So let's start.

We will create 2 endpoint signup, log in.

  • POST /login user login
  • GET /register user signup

Let's define the routes in web.php which is inside routes folder

$router->group(['prefix'=>'api'], function() use($router){

    $router->post('register', 'userController@register');
    $router->post('login', 'userController@login');

    $router->get('articles', 'ArticleController@index');
    $router->post('article', 'ArticleController@create');   
    $router->put('article/{id}', 'ArticleController@update');
    $router->get('article/{id}', 'ArticleController@show');
    $router->delete('article/{id}', 'ArticleController@delete');
});

Step 1: User Migration

Create a table for users with id auto increment name, password, email. To create the table, run:

 php artisan make:migration create_table_users --create=users

This will create a _create_table_users.php file inside the database/migrations/ folder. Now edit the file Add the following code

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTableUsers extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique()->notNullable();
            $table->string('password');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Now run the following command to execute the migration.this will create the user's table and you can see the table in PHPMyAdmin

php artisan migrate

You may also like: Lumen Installation Guide

Step 2: respondWithToken method

Add global respondWithToken method in app/Http/Controller directory inside Controller.php file

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
use Laravel\Lumen\Routing\Controller as BaseController;

class Controller extends BaseController
{
    protected function respondWithToken($token)
    {
        return response()->json([
            'token' => $token,
            'token_type' => 'bearer',
            'expires_in' => Auth::factory()->getTTL() * 60
        ], 200);
    }
}

Step 3: Install the JWT package

composer require tymon/jwt-auth

Uncomment Authenticate, AuthServiceProvider & add the LumenServiceProvider service provider in the bootstrp/app.php config file as follows:

$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
]);


// $app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);

$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);

Generate the secret key in the .env file by running this command:

php artisan jwt:secret

// it will add a variable in .env file something like this
//JWT_SECRET=2RWYYTKND97wMfoXHg14kbmqIpe4YMKoKEdfeT7Js3wnaghyvMXDhxgBu9zGJTtO

Step 4: User.php

Modified the user.php for JWT authentication define 2 abstract methods getJWTIdentifier & getJWTCustomClaims after adding this your user.php look like below.

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;

use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
    use Authenticatable, Authorizable;

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

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = [
        'password',
    ];

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

    public function getJWTCustomClaims()
    {
        return [];
    }
}

Step 5: config/app.php

Next, Create a directory config and inside this create app.php file and paste the below code

<?php

return [
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

    'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

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

Step 6: UserController

Next, Create a userController.php file inside app/Http/Controller directory and paste the below code

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function register(Request $request)
    {
        //validate incoming request 
        $this->validate($request, [
            'name' => 'required|string',
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed',
        ]);

        try {

            $user = new User;
            $user->name = $request->input('name');
            $user->email = $request->input('email');
            $plainPassword = $request->input('password');
            $user->password = app('hash')->make($plainPassword);

            $user->save();            
            return response()->json(['user' => $user,'message'=>'User successful added'], 201);

        } catch (\Exception $e) {
            return response()->json(['message' => 'Something went wrong,Pleae try again!']);
        }
    }

    public function login(Request $request)
    {
        //validate email & password request 
        $this->validate($request, [
            'email' => 'required|string',
            'password' => 'required|string',
        ]);

        $credentials = $request->only(['email', 'password']);

        if (! $token = Auth::attempt($credentials)) 
            return response()->json(['message' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }
}

Step 7: Auth

Finally, add the Auth integration in all your existing Controller. In the last article, I have created an ArticleController.php I am adding the authentication in Controller. After adding auth middleware you need to pass token in a header which you received in login response.

<?php

namespace App\Http\Controllers;

use App\Article;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class ArticleController extends Controller{

    public function __construct()
    {
        $this->middleware('auth');
    }

    public function create(Request $request){

        $article = Article::create($request->all());

        return response()->json($article);

    }

    public function update(Request $request, $id){

        $article  = Article::find($id);
        $article->title = $request->input('title');
        $article->description = $request->input('description');
        $article->publisher = $request->input('publisher');
        $article->save(); 
        return response()->json($article);
    }  

    public function delete($id){
        $article  = Article::find($id);
        $article->delete();

        return response()->json('Removed successfully.');
    }

    public function show($id) {
        $article = Article::find($id);
        return response()->json($article);
    }

    public function index(){ 
        $articles  = Article::all(); 
        return response()->json($articles);

    }
}
?>

That's It. Thanks for the reading. Hope this will help!

Related Articles