Laravel 10 REST API with Passport Authentication Tutorial

Last Updated on by in Laravel
Do you want to know how to create a secure REST API using Passport in Laravel? If you have the same question, then with the conventional coherence about Laravel and Passport, we will learn the same thing.In Laravel, you can take the holistic approach to build API. You won’t have to put intensive efforts; instead, you can give precedence to security. As far as security is concerned, Laravel Passport takes care of security and allows you to create Auth Token to provide authentication to users.

In this tutorial, we will learn to create robust, fast, and secure CRUD (CREATE, READ, UPDATE, DELETE) RESTful Authentication API with Passport Package in Laravel by following all the imperatives needed to be followed.

What is API (Application Programming Interface)?

API refers to the Application Programming Interface. It is a set of routines, protocols, and tools for creating software applications. An API interface makes communication possible between various software components.

In software development, API is a URL that handles the data for the web application through HTTP Requests GET, POST, UPDATE & DELETE, and manages the CRUD operations.

What is REST API?

Representational state transfer (REST) is a software architectural style that defines a set of constraints to be used for creating Web services. Web services that conform to the REST architectural style, called RESTful Web services, provide interoperability between computer systems on the Internet. RESTful Web services allow the requesting systems to access and manipulate textual representations of Web resources by using a uniform and predefined set of stateless operations. Other kinds of Web services, such as SOAP Web services, expose their own arbitrary sets of operations.
source: wikipedia

Install New Laravel Project

Let’s invoke the following command in the terminal to install a brand new Laravel application.

composer create-project laravel/laravel laravel-passport-auth --prefer-dist

Set Up Database

You must have either MAMP or XAMPP installed on your local development system, and the local server must be turned on.

This step explains how to make consensus between laravel and database, Incorporate the following code in .env file to establish the connection between both parties.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

If you are using MAMPP, then you might get the given below error while running migration. Please add the following line of code right after your database configuration inside the .env file.

DB_HOST=localhost;unix_socket=/Applications/MAMP/tmp/mysql/mysql.sock

Install Passport Package

On an impulse, the second step leads us to install the passport package through Composer package manager. Without further ado run the following command in your terminal.

composer require laravel/passport

Ideally, we have to use the default migration to create a new table in the MySQL database.

php artisan migrate

Next, generate token keys for strengthening the security and restrain hackers from deteriorating the security of our applications.

php artisan passport:install

Configure Passport Module

We need to focus on some nitty-gritty to configure the Passport package in the Laravel application. First, open app/Models/User.php file and include HasApiTokens trait inside the User model, as mentioned below.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens;

    /**
     * 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',
    ];
}

Next, open app/Providers/AuthServiceProvider.php file and register the registerPolicies() method inside the boot() function, It will evoke the required routes.

<?php

namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

use Laravel\Passport\Passport;


class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];


    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
    }
}

Register the PassportServiceProvider class in providers array inside the config/app.php file:

'providers' => [
        ...
        ... 
        ...
        Laravel\Passport\PassportServiceProvider::class,

    ],

Configure driver for the Passport, get inside the config/auth.php file and make the changes as shown below.

<?php
    return [
    ....
    ....
    
        'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
    
            'api' => [
                'driver' => 'passport',
                'provider' => 'users',
            ],
        ],
    
    ....
    ....
]

Create Posts Model & Run Migration

To make the consensus between client and server, we will have to create the Post model by executing the below command.

php artisan make:model Post -m

After executing the above command, you will see the archetype of posts migration file in database/migrations/timestamp_create_posts_table. Here, you have to add some values to create the internal coherence using Model.

<?php

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

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedBigInteger('user_id');
            $table->text('title');
            $table->longText('description');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users');  
        });
    }

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

Next, create the app/Models/Post.php file and register the following values inside the $fillable array.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
    protected $fillable = [
        'title', 'description'
    ];    
}

Then, run the migration by using the below command.

php artisan migrate

Create a New Controller

Let us take another imperative in the consideration and, on the same impetus, execute the following command. It will create a new controller in our laravel app to create a login and registration REST API.

php artisan make:controller PassportAuthController

Controller is the quintessential file in Laravel application development. So, without further insert the given below code in PassportAuthController.php file.

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;

class PassportAuthController extends Controller
{
    /**
     * Registration
     */
    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|min:4',
            'email' => 'required|email',
            'password' => 'required|min:8',
        ]);
 
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password)
        ]);
       
        $token = $user->createToken('LaravelAuthApp')->accessToken;
 
        return response()->json(['token' => $token], 200);
    }
 
    /**
     * Login
     */
    public function login(Request $request)
    {
        $data = [
            'email' => $request->email,
            'password' => $request->password
        ];
 
        if (auth()->attempt($data)) {
            $token = auth()->user()->createToken('LaravelAuthApp')->accessToken;
            return response()->json(['token' => $token], 200);
        } else {
            return response()->json(['error' => 'Unauthorised'], 401);
        }
    }   
}

Before we move to next step, establish consensus between Post and User model. Gradually incorporate the following method inside the app/Models/User.php file.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens;

    /**
     * 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 posts()
    {
        return $this->hasMany(Post::class);
    }    
}

Run command to create Post Controller.

php artisan make:controller PostController

Add the following code in PostController.php file.

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = auth()->user()->posts;
 
        return response()->json([
            'success' => true,
            'data' => $posts
        ]);
    }
 
    public function show($id)
    {
        $post = auth()->user()->posts()->find($id);
 
        if (!$post) {
            return response()->json([
                'success' => false,
                'message' => 'Post not found '
            ], 400);
        }
 
        return response()->json([
            'success' => true,
            'data' => $post->toArray()
        ], 400);
    }
 
    public function store(Request $request)
    {
        $this->validate($request, [
            'title' => 'required',
            'description' => 'required'
        ]);
 
        $post = new Post();
        $post->title = $request->title;
        $post->description = $request->description;
 
        if (auth()->user()->posts()->save($post))
            return response()->json([
                'success' => true,
                'data' => $post->toArray()
            ]);
        else
            return response()->json([
                'success' => false,
                'message' => 'Post not added'
            ], 500);
    }
 
    public function update(Request $request, $id)
    {
        $post = auth()->user()->posts()->find($id);
 
        if (!$post) {
            return response()->json([
                'success' => false,
                'message' => 'Post not found'
            ], 400);
        }
 
        $updated = $post->fill($request->all())->save();
 
        if ($updated)
            return response()->json([
                'success' => true
            ]);
        else
            return response()->json([
                'success' => false,
                'message' => 'Post can not be updated'
            ], 500);
    }
 
    public function destroy($id)
    {
        $post = auth()->user()->posts()->find($id);
 
        if (!$post) {
            return response()->json([
                'success' => false,
                'message' => 'Post not found'
            ], 400);
        }
 
        if ($post->delete()) {
            return response()->json([
                'success' => true
            ]);
        } else {
            return response()->json([
                'success' => false,
                'message' => 'Post can not be deleted'
            ], 500);
        }
    }
}

Define API Routes

Now, we will define API routes. Go to routes/api.php file and declare the foundational code.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PassportAuthController;
use App\Http\Controllers\PostController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::post('register', [PassportAuthController::class, 'register']);
Route::post('login', [PassportAuthController::class, 'login']);

Route::middleware('auth:api')->group(function () {
    Route::resource('posts', PostController::class);
});

Test Laravel 10 Passport API

Eventually, we have completed all the foundational steps that were required to build REST API with Passport authentication in Laravel. Now, the time has come to test out the API, so run the following command to start the laravel app.

php artisan serve

We have to rely on Postman for testing our newly formed endpoints.

Register API:
You can test the Laravel Passport API for registering the user:

Please open the Postman app and Headers tab, define "Accept": application/json header value:

Set Header

http://localhost:8000/api/register

Laravel Passport User Registration

Login Passport API:
After sign up, copy the Bearer token, set into the Headers section in the Postman app. Check out the Laravel Passport Endpoint for logging-in:

http://localhost:8000/api/login

Passport Login API

Passport Post Create API:

http://localhost:8000/api/posts

To perform the CRUD operation, we need to set the correct authenticity. After successful registration and login, you will receive the access token. The manifestation of access token creates coherence with authorization, and It establishes secure communication with the server. You need to set this access token as a Bearer Token in the Authorization header.

'headers' => [
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '. $accessToken,
]

Passport Post Create API

Laravel Passport Create API

Post List API:

http://localhost:8000/api/posts

Post List API

Show Single Post API:

http://localhost:8000/api/posts/{id}

Show Single Post API

Post Update API:

http://localhost:8000/api/posts/{id}

Post Update API

Post Delete API:

http://localhost:8000/api/posts/{id}

Post Delete API

The Bottom Line

Eventually, we have completed the Laravel Passport API Tutorial. In this tutorial, we have shed light on every aspect needed to build secure REST APIs in Laravel.

We have gone through every foundation step and put everything at its place without falling into the trap of procrastination. This tutorial is useful for those who are new and want to try their hands to create a secure REST API with Passport in Laravel.

I have tried to shape things from my outlook on the entire journey, i haven’t been skeptical about anything. Anyhow, If i have skipped anything due to recklessness, you must download the full code of this tutorial from the GitHub.