Iqbal Syahrul Siddiq
Posted on August 20, 2023
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
but, if you want to using specific version of lumen, you can run command below
composer create-project laravel/lumen blog "5.*.*"
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
- Create a new migration file, run this command
php artisan make:migration create_users_table
- 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');
}
}
- Run the migration
php artisan migrate
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:*
Generate JWT Secret Key
Generate key secret JWT, run command below
php artisan jwt:secret
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
- 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);
- 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
]
]
];
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 [];
}
}
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
]);
}
}
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');
});
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
Running Lumen
Run lumen with this command
php -S localhost:8000 -t public
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
Posted on August 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.