DEV Community

Cover image for Lumen Tutorial : How to build a JWT Authenticated API with Lumen
Iqbal Syahrul Siddiq
Iqbal Syahrul Siddiq

Posted on • Edited on

Lumen Tutorial : How to build a JWT Authenticated API with Lumen

A JSON web token(JWT) is JSON Object which is used to securely transfer information over the web(between two parties). It can be used for an authentication system and can also be used for information exchange.

The token is mainly composed of header, payload, signature. These three parts are separated by dots(.). JWT defines the structure of information we are sending from one party to the another, and it comes in two forms – Serialized, Deserialized.

The Serialized approach is mainly used to transfer the data through the network with each request and response. While the deserialized approach is used to read and write data to the web token.

In this tutorial, i would like to show you how to build a JWT Authenticated API with Lumen 8.

Let's code !!

Install Lumen

First step, you have to install new lumen project. If you want to use latest version of lumen, you can run command below :

composer create-project --prefer-dist laravel/lumen blog
Enter fullscreen mode Exit fullscreen mode

but, if you want to using specific version of lumen, you can run command below

composer create-project laravel/lumen blog "5.*.*"
Enter fullscreen mode Exit fullscreen mode

you just have to change main version number (5, 6, 7, 8, etc)

Make Migration for Database

  • Make sure, your env file connected to some database address
DB_CONNECTION=mysql
DB_HOST=type-your-host-here
DB_PORT=3306
DB_DATABASE=type-your-db-here
DB_USERNAME=type-your-username
DB_PASSWORD=type-your-password
Enter fullscreen mode Exit fullscreen mode
  • Create a new migration file, run this command
php artisan make:migration create_users_table
Enter fullscreen mode Exit fullscreen mode
  • Open migration file, and add code below
<?php

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

class CreateUsersTable 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();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

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

Enter fullscreen mode Exit fullscreen mode
  • Run the migration
php artisan migrate
Enter fullscreen mode Exit fullscreen mode

This command, will execute migration file and create new tables in your database.

Install JWT Package

install jwt-auth via composer

composer require tymon/jwt-auth:*
Enter fullscreen mode Exit fullscreen mode

Generate JWT Secret Key

Generate key secret JWT, run command below

php artisan jwt:secret
Enter fullscreen mode Exit fullscreen mode

Setup Folder & Important Config File

  • Create new folder, named it config (same level with app folder)
  • You have to copy file from vendor/tymon/jwt-auth/config/config.php to config folder, and rename file to jwt.php

  • Next, make new file inside config folder, auth.php

Image description

  • Open file app.php (bootstrap/app.php), edit and add this code
// Uncomment this line
$app->withFacades();
$app->withEloquent();

// Add this line
$app->configure('jwt');
$app->configure('auth');

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

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

// Add this line in the same file:
$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);
Enter fullscreen mode Exit fullscreen mode
  • Open auth.php (config/auth.php) add this code
<?php

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

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

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => \App\Models\User::class
        ]
    ]
];
Enter fullscreen mode Exit fullscreen mode

Create Model

Let's make new file model, User.php (app/models/user.php), add code below :

<?php

namespace App\Models;

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

//this is new
use Tymon\JWTAuth\Contracts\JWTSubject;

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

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}
Enter fullscreen mode Exit fullscreen mode

Create Controller

Next, you have to make new controller file, AuthController (app/http/controllers/AuthController), add thic code :

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class AuthController extends Controller
{

    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login', 'refresh', 'logout']]);
    }
    /**
     * Get a JWT via given credentials.
     *
     * @param  Request  $request
     * @return Response
     */
    public function login(Request $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);
    }

     /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth()->user());
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth()->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'user' => auth()->user(),
            'expires_in' => auth()->factory()->getTTL() * 60 * 24
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Setup Route

Open web.php file (routes/web.php), add this code

<?php

/** @var \Laravel\Lumen\Routing\Router $router */

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

$router->get('/', function () use ($router) {
    return $router->app->version();
});

$router->get('/get-key', function() {
    return \Illuminate\Support\Str::random(32);
});

Route::group([

    'prefix' => 'api'

], function ($router) {
    Route::post('login', 'AuthController@login');
    Route::post('logout', 'AuthController@logout');
    Route::post('refresh', 'AuthController@refresh');
    Route::post('user-profile', 'AuthController@me');

});
Enter fullscreen mode Exit fullscreen mode

Add Encryption key Application

You can't run php artisan key:generate in lumen (like in Laravel), so you have to generate manually by call route /get-key

Open browser, visit this link http://localhost:8000/get-key , copy and paste the key to APP_KEY in env file

Refresh ENV Setup

After you change env file, you have to run

php artisan cache:clear
Enter fullscreen mode Exit fullscreen mode

Running Lumen

Run lumen with this command

php -S localhost:8000 -t public
Enter fullscreen mode Exit fullscreen mode

Open Postman to test your API endpoint's

_You can clone example code by this link : _ https://gitlab.com/open-for-public/lumen-restfull-api-with-jwt-authentication.git

Top comments (1)

Collapse
 
fredlag profile image
fredlag

Thanks for the sharing security with jwt is very important