Laravel 7 RESTFul API with JSON Web Token (JWT)
We are going to learn how to delvelop Laravel RESRFul API with JSON Web Token (JWT).
1. Create Laravel porject
To install new laravel project run the command
laravel new laravel-rest-api-jwt-auth
To go to the project directory run the command
cd laravel-rest-api-jwt-auth
Open the project with your favorite code editor and put the credentials of database in .env file
DB_DATABASE=laravel_rest_api_jwt_auth
DB_USERNAME=root
DB_PASSWORD=
2. Install jwt-auth package
See the documentation here
To install the package run the command
composer require tymon/jwt-auth:dev-develop --prefer-source
To publish the package configurations run the command
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
To generating JWT authentication keys run the command
php artisan jwt:secret
Now we will registering JWT middleware. Open app/Http/Kernel.php and add this line
protected $routeMiddleware = [
...
'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class
];
3. Create routes
Now we will create our routes in routes/api.php
Route::post("login", "AuthController@login");
Route::post("register", "AuthController@register");
Route::group(["middleware" => "auth.jwt"], function () {
Route::get("logout", "AuthController@logout");
Route::resource("tasks", "TaskController");
});
4. Update User model
Open app/User.php file and add bolded lines
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;
And add these methods
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
5. Create AuthController
Now we are going to creating AuthController for Login and Registration, run the command
php artisan make:controller AuthController
Open app\Http\Controllers\AuthController.php file and add this property
public $loginAfterSignUp = true;
Now add login method
public function login(Request $request)
{
$credentials = $request->only("email", "password");
$token = null;
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json([
"status" => false,
"message" => "Unauthorized"
]);
}
return response()->json([
"status" => true,
"token" => $token
]);
}
Here is our register method
public function register(Request $request)
{
$this->validate($request, [
"name" => "required|string",
"email" => "required|email|unique:users",
"password" => "required|string|min:6|max:10"
]);
$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([
"status" => true,
"user" => $user
]);
}
And this is our last and final logout method
public function logout(Request $request)
{
$this->validate($request, [
"token" => "required"
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
"status" => true,
"message" => "User logged out successfully"
]);
} catch (JWTException $exception) {
return response()->json([
"status" => false,
"message" => "Ops, the user can not be logged out"
]);
}
}
Finally we need to use this Classes at the top
use JWTAuth;
use App\User;
use Tymon\JWTAuth\Exceptions\JWTException;
Here is our completed AuthController
namespace App\Http\Controllers;
use JWTAuth;
use App\User;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
class AuthController extends Controller
{
public $loginAfterSignUp = true;
public function login(Request $request)
{
$credentials = $request->only("email", "password");
$token = null;
if (!$token = JWTAuth::attempt($credentials)) {
return response()->json([
"status" => false,
"message" => "Unauthorized"
]);
}
return response()->json([
"status" => true,
"token" => $token
]);
}
public function register(Request $request)
{
$this->validate($request, [
"name" => "required|string",
"email" => "required|email|unique:users",
"password" => "required|string|min:6|max:10"
]);
$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([
"status" => true,
"user" => $user
]);
}
public function logout(Request $request)
{
$this->validate($request, [
"token" => "required"
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
"status" => true,
"message" => "User logged out successfully"
]);
} catch (JWTException $exception) {
return response()->json([
"status" => false,
"message" => "Ops, the user can not be logged out"
]);
}
}
}
6. Create Task Model, Migration and Controller
To create Task model, migration and controller run the command
php artisan make:model Task -mcr
Open task migration file form database\migrations and add this schema to up method
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('details');
$table->unsignedBigInteger('created_by');
$table->timestamps();
$table->foreign('created_by')->references('id')->on('users')->onDelete('cascade');
});
Open app/User.php file and add this method at end
public function tasks()
{
return $this->hasMany(Task::class, 'created_by', 'id');
}
Here is our completed User model
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;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
public function tasks()
{
return $this->hasMany(Task::class, 'created_by', 'id');
}
}
7. Migrate database and insert dummy data
To migrate run the command
php artisan migrate
To insert dummy data follow the steps bellow
Open database/factories/UserFactory.php
Replace password with 'password' => bcrypt('123456'),
$factory->define(Task::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'details' => $faker->sentence,
'created_by' => rand(1, 10)
];
});
use App\Task; at top
Here is our completed UserFactory.php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use App\Task;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => bcrypt("123456"),
'remember_token' => Str::random(10),
];
});
$factory->define(Task::class, function (Faker $faker) {
return [
'title' => $faker->sentence,
'details' => $faker->sentence,
'created_by' => rand(1, 10)
];
});
Now run these commands to insert some dummy data
php artisan tinker
factory(App\User::class, 10)->create()
factory(App\Task::class, 50)->create()
8. Task CRUD functionality
Open app\Http\Controllers\TaskController.php
add user property and construct method
protected $user;
public function __construct()
{
$this->user = JWTAuth::parseToken()->authenticate();
}
Add index method to get the task list those are created by the logged in user
public function index()
{
$tasks = $this->user->tasks()->get(["id", "title", "details", "created_by"])->toArray();
return $tasks;
}
Here is our store method to store tast data with the logged in user id
public function store(Request $request)
{
$this->validate($request, [
"title" => "required",
"details" => "required"
]);
$task = new Task();
$task->title = $request->title;
$task->details = $request->details;
if ($this->user->tasks()->save($task)) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be saved."
], 500);
}
}
This is update method to update task data with logged in user id
public function update(Request $request, Task $task)
{
$this->validate($request, [
"title" => "required",
"details" => "required"
]);
$task->title = $request->title;
$task->details = $request->details;
if ($this->user->tasks()->save($task)) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be updated."
], 500);
}
}
And final delete method to delete task data
public function destroy(Task $task)
{
if ($task->delete()) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be deleted."
]);
}
}
This is our completed TaskController
namespace App\Http\Controllers;
use JWTAuth;
use App\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
protected $user;
public function __construct()
{
$this->user = JWTAuth::parseToken()->authenticate();
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$tasks = $this->user->tasks()->get(["id", "title", "details", "created_by"])->toArray();
return $tasks;
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
"title" => "required",
"details" => "required"
]);
$task = new Task();
$task->title = $request->title;
$task->details = $request->details;
if ($this->user->tasks()->save($task)) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be saved."
], 500);
}
}
/**
* Display the specified resource.
*
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function show(Task $task)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function edit(Task $task)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Task $task)
{
$this->validate($request, [
"title" => "required",
"details" => "required"
]);
$task->title = $request->title;
$task->details = $request->details;
if ($this->user->tasks()->save($task)) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be updated."
], 500);
}
}
/**
* Remove the specified resource from storage.
*
* @param \App\Task $task
* @return \Illuminate\Http\Response
*/
public function destroy(Task $task)
{
if ($task->delete()) {
return response()->json([
"status" => true,
"task" => $task
]);
} else {
return response()->json([
"status" => false,
"message" => "Ops, task could not be deleted."
]);
}
}
}
9. Test the project
To test the project please watch the video. This will help you in better way.
10. Source File
To get completed project with source file visit this github link