JWT authentication provides a secure way to transmit data between the client and server. Using JWT we can transfer data and information between client and server. In this post, we will look at how we can create a rest API security using JWT authentication and Laravel based API.
Generally, We use rest API services on different types of platforms such as web, android and IOS. If you are familiar with front-end development languages like ReactJs, AngularJs & VueJs then you have idea to use API services to create dynamic front-end web application.
Why we should use JWT token based authentication?
If you have a look in the config/auth.php file, You can find out laravel default authentication configuration. Laravel’s authentication functionality is based on the guards and providers. Here providers defines the guard’s configuration and guards control each request authentication
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', 'hash' => false, ], ],
In other way, We can use session & cookies if our backend application and client and server application are on same domain. But in the case of an API services, if client on a different domain and your backend application on a separate domain. In this case we will face CORS ( Cross Origin Resource Sharing ) errors.
Now, we will start by installing Laravel and create an API that will use the JWT authentication. We will be create an API for Blogs Management with the JWT Authentication.
Roadmap that we will be create in this post
- Create a new account.
- Login
- Logout
- Get all blogs related to a User.
- Get a specific blog by blog Id.
- Create a new blog to User’s blog list.
- Update existing blog.
- Delete blog.
Here are the two Eloquent models User and Blog.
A User will requires:
name
email
password
A Blog will required:
title
description
user id
Now using below command we will create new Laravel application.
composer create-project laravel/laravel JWTAuthApp Then cd JWTAuthApp
After successfully laravel installation, We need to install JWT authentication package.
You can find out many JWT laravel packages on https://packagist.org/?query=laravel%20jwt
Here we use this package link (https://github.com/tymondesigns/jwt-auth) with laravel.
Run the below command in the terminal to install this package.
composer require tymon/jwt-auth:dev-develop --prefer-source
Run the below command for publish the package configurations.
php artisan vendor:publish
After sun above command you will get list of package to publish so choose Tymon\JWTAuth\Providers\LaravelServiceProvider and then hit enter. also this comman has generated a jwt.php configuration file in the config folder.
Using below command we will generating JWT authentication Keys.
php artisan jwt:secret
Now, Key will generated somtheing like :
jwt-auth secret [SOMtsRN3rlwlhVDOgSWRQRBZ5F29u0t1b4SmfwA06bmmzCVf66KkcXUgpcDr7FAc] set successfully.
JWT Middleware
JWT package comes with a pre built middle ware which we can use for our API routes. Open the app/Http/Kernel.php file and register this middle ware with the name auth.jwt.
'auth.jwt'=>\Tymon\JWTAuth\Http\Middleware\Authenticate::class,
This middleware will check request- if the user is authenticated by checking the token sent with the request if user is not authenticated it will throw an UnauthorizedHttpException exception.
In this section, we will setup our routes required for our this application. Open the routes/api.php file and copy the below routes to this file.
Route::post('signin', 'APIController@login'); Route::post('signup', 'APIController@register'); Route::group(['middleware' => 'auth.jwt'], function () { Route::get('logout', 'APIController@logout'); Route::get('blogs', 'BlogController@index'); Route::get('blogs/{id}', 'BlogController@show'); Route::post('blogs', 'BlogController@store'); Route::put('blogs/{id}', 'BlogController@update'); Route::delete('blogs/{id}', 'BlogController@destroy'); });
User Model & JWT Interface
Open the app/User.php file and update with the below one.
namespace App; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { use Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; protected $hidden = [ 'password', 'remember_token', ]; protected $casts = [ 'email_verified_at' => 'datetime', ]; public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } }
User registration will require name, email, and password. So let’s create the form request class to handle this validation. Request class includes actual logic of data that required in API.
We will create a new form request class RegistrationFormRequest by running the command below.
php artisan make:request RegistrationFormRequest
It will create RegistrationFormRequest.php file in the app/Http/Requests folder.
Open this class and replace the code with below one:
namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class RegistrationFormRequest extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'name' => 'required|string', 'email' => 'required|email|unique:users', 'password' => 'required|string|min:6|max:10' ]; } }
Creating API Controller for Sign-In, Sign-Up & Logout
Now, we will create a new controller class and name it APIController. Here we will run the below artisan command to generate this controller.
php artisan make:controller APIController
This will generate a new controller in the app/Http/Controllers folder. Open this controller and update with the below controller class.
namespace App\Http\Controllers; use JWTAuth; use App\User; use Illuminate\Http\Request; use Tymon\JWTAuth\Exceptions\JWTException; use App\Http\Requests\RegistrationFormRequest; class APIController extends Controller { public $loginAfterSignUp = true; public function login(Request $request) { $input = $request->only('email', 'password'); $token = null; if (!$token = JWTAuth::attempt($input)) { return response()->json([ 'success' => false, 'message' => 'Invalid Email or Password', ], 401); } return response()->json([ 'success' => true, 'token' => $token, ]); } public function logout(Request $request) { $this->validate($request, [ 'token' => 'required' ]); try { JWTAuth::invalidate($request->token); return response()->json([ 'success' => true, 'message' => 'User logged out successfully' ]); } catch (JWTException $exception) { return response()->json([ 'success' => false, 'message' => 'Sorry, the user cannot be logged out' ], 500); } } public function register(RegistrationFormRequest $request) { $user = new User(); $user->name = $request->name; $user->email = $request->email; $user->password = bcrypt($request->password); $user->save(); if ($this->loginAfterSignUp) { return $this->login($request); } return response()->json([ 'success' => true, 'data' => $user ], 200); } }
So far, We have build user registration, login and logout functionality. As you can see in above code we have used
RegistrationFormRequestin register method and return json response using laravel default method.
Blog Model and Migration
Now we will create a new model Blog and perform a CRUD operation on it. we will need to create a model, migration, and controller. Run the below command in command line terminal to generate model, migration, and controller altogether.
php artisan make:model Blog -mc
Above command will create a new migration file in the database/migrations folder. Open that migration file and update it with the below one.
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateTBlogsTable extends Migration { public function up() { Schema::create('blogs', function (Blueprint $table) { $table->bigIncrements('id'); $table->bigInteger('user_id')->unsigned(); $table->string('title'); $table->text('description')->nullable(); $table->foreign('user_id') ->references('id') ->on('users') ->onDelete('cascade'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('blogs'); } }
Now, setup the database configuration in .env file and run the below command to migrate all tables.
php artisan migrate
Now, open the Blog model from the app/ folder and update the model with below one.
namespace App; use Illuminate\Database\Eloquent\Model; class Blog extends Model { protected $table = 'blogs'; protected $guarded = []; }
A user can have many blogs. Open the User model and add the below method in it.
public function blogs() { return $this->hasMany(Blog::class); }
In the above method, we have added a One To Many relationship.
Open the BlogController from app/Http/Controllers folder and update with the below one.
namespace App\Http\Controllers; use JWTAuth; use App\Blog; use Illuminate\Http\Request; class BlogController extends Controller { protected $user; public function __construct() { $this->user = JWTAuth::parseToken()->authenticate(); } }
In above code, The parseToken() method will get the token from the request object and authenticate() method will authenticate the user by token. So here we have to pass token with each API request. If token is not match with user then below methods are not accessible.
Next, we will add the index() method which will return the all blogs for a currently authenticated user.
public function index() { $blogs = $this->user->blogs()->get(['title', 'description'])->toArray(); return $blogs; }
In the above method, we are getting all blogs for a user and storing them to an array.
Now, add a new method named show() which will get a blog by its id.
public function show($id) { $blog = $this->user->blogs()->find($id); if (!$blog) { return response()->json([ 'success' => false, 'message' => 'Sorry, blog with id ' . $id . ' cann't be found.' ], 400); } return $blog; }
Next, add the store() method which will be responsible for saving a blog for user.
public function store(Request $request) { $this->validate($request, [ 'title' => 'required', 'description' => 'required', ]); $blog = new Blog(); $blog->title = $request->title; $blog->description = $request->description; if ($this->user->blogs()->save($blog)) return response()->json([ 'success' => true, 'blog' => $blog ]); else return response()->json([ 'success' => false, 'message' => 'Sorry, blog could not be added.' ], 500); }
Now, adding the update method for update blog.
public function update(Request $request, $id) { $blog = $this->user->blogs()->find($id); if (!$blog) { return response()->json([ 'success' => false, 'message' => 'Sorry, blog with id ' . $id . ' cannot be found.' ], 400); } $updated = $blog->fill($request->all())->save(); if ($updated) { return response()->json([ 'success' => true ]); } else { return response()->json([ 'success' => false, 'message' => 'Sorry, blog could not be updated.' ], 500); } }
Finally, we will add the destroy() method.
public function destroy($id) { $blog = $this->user->blogs()->find($id); if (!$blog) { return response()->json([ 'success' => false, 'message' => 'Sorry, blog with id ' . $id . ' cannot be found.' ], 400); } if ($blog->delete()) { return response()->json([ 'success' => true ]); } else { return response()->json([ 'success' => false, 'message' => 'Blog could not be deleted.' ], 500); } }
That’s all for the BlogController, we have developed the blogs CRUD successfully. Now it’s time for testing.
For Testing API these services. Open the command line terminal and run the below command.
php artisan serve
To test this REST api I am using the Postman which is a coefficient environment for building APIs. You can read more about Postman on their website. Link (https://www.getpostman.com/)
Here is API to use:
Above both APIs will send token, using that token you can get blogs and perform other CURD operation related to blogs.
Download code using github link: https://github.com/amitverma-startbitsolutions/laravel-jwt-authentication
In this post, we have successfully created the Rest API using JWT Authentication with Laravel.
Have you any guide for Jobposting schema in Codeignator?
I have created a website CBTQBank and implemented jobposting schema but it is showing error in GWT.
My website – cbtqbank.com