Laravel 10 REST API using Passport Authentication


Laravel 10 REST API using Passport Authentication

Download

Today in this tutorial, we will learn about how to build Laravel 10 REST API using Passport authentication. We will learn it with example application in Laravel REST API authentication with Passport with step by step guide.

We will develop very simple Laravel 10 Passport API for authentication so that anyone can easily understand it, building API is very easy with Laravel Passport and we can easily build Laravel 10 Passport SPA API.

Previously, we have also shared how to develop a Laravel 10 REST API using Sanctum Authentication, Sanctum is another package in Laravel which is also used for building APIs.

What is API?

Before start developing the API, lets learn what is an API. In simple words, API (application programming interface) is just a way communication between two or more computer programs.

These APIs are mostly used for web and mobile applications development, this is why developing RESTful APIs are very important to learn for all web and mobile application developers.

What is Laravel Passport?

We will use Laravel Passport which provides a complete OAuth2 server implementation and also issue API tokens for authentication and developing APIs for SPAs (single page applications) which are used in web and mobile applications.

Although, you can use Laravel Sanctum Authentication as well for issuing tokens. But in this example we will learn how to use Laravel Passport by building Restful APIs.

We will use access tokens for registered users, we can generate multiple tokens using Laravel Passport which will help us to access all protected routes/end points of our application.

For this example, we are using the Laravel 10.10 and Passport 11.10 versions.

Laravel Passport help us to generate access tokens for the protected routes/end points which will be stored in our oauth_access_tokens table.

We are using Laravel Passport only for the protected routes of our application. To access public routes, we do not need to use the access token.

Application Flow

In our example application, we will first create a products table which will hold all products information. There will be two columns in products table with name as name and description.

We will develop APIs for Laravel 10 custom user registration and login as we will generate access tokens for registered users using Laravel Passport. We will build user logout API as well.

In our app, user registration and login are public routes, these routes will return the access token to access the protected routes of our app by passing these tokens as a bearer token. Logout route is a protected route therefore we will pass the access token to logout from our Laravel application.

We will pass access tokens to create, update and delete product from the database, as these are protected routes and we can not perform these operations until we pass the correct access tokens with them.

To achieve this objective we will develop CRUD operations API for our products.

In order to view all products, single product and search products, we do not need token as these are public routes and we can access public routes without access tokens.

Before start building, you must be aware of how to perform CRUD operations in Laravel, you can also checkout the tutorial of Laravel 10 CRUD application.

Now without further delay, lets start developing a Laravel 10 REST API authentication application with Laravel Passport example.

Steps to Create Laravel 10 REST API using Passport Authentication

Follow the below step by step guide to create a Laravel 10 REST API using Passport authentication application.

  1. Install Latest Laravel App
  2. Install or Enable PHP’s Sodium Extension
  3. Configure Database Credentials
  4. Install Laravel Passport
  5. Add API Driver in Guards in auth.php
  6. Add HasApiTokens Traits in User Model
  7. Create and Update LoginRegister Controller
  8. Create and Update Product Model with Migration and Model API Resource Controller
  9. Define API Endpoints in routes/api.php
  10. Migrate Product Table to Database
  11. Run Laravel Development Server & Test the Application

1. Install Latest Laravel App

Install Laravel 10 application with name laravel-10-passport-api by running the below command on terminal or command prompt.

composer create-project --prefer-dist laravel/laravel laravel-10-passport-api

Go to the laravel-10-passport-api directory by running the below command.

cd laravel-10-passport-api

2. Install or Enable PHP’s Sodium Extension

Now, before moving ahead make sure that PHP’s Sodium extension is enabled, we are using XAMPP for PHP.

In XAMPP, we need to enable PHP’s Sodium extension. Typically if installed in C drive. Just go to C:\xampp\php\php.ini and remove the semi-colon (;) before extension=sodium and restart apache server.

//Before
;extension=sodium
//After
extension=sodium

Normally, this resolves the issue of mostly users. In case if your issue is not resolved make sure that libsodium.dll file exist in PHP directory in XAMPP.

Alternatively, you can install the latest XAMPP, complete and step by step guide is available here about how to Install XAMPP on Windows.

3. Configure Database Credentials

Now we need to update the database credentials which are database name, username and password. All you need is to update the .env file which is available on the root directory in your application.

Open the .env file and update it with your database credentials like below.

Database Credentials:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_db_name
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password

4. Install Laravel Passport

Now install Laravel Passport in your application by running the below command.

composer require laravel/passport

Now make sure that your database is running, then we need to migrate all migrations, just run the below command to migrate all Laravel tables along with Laravel passport OAuth2 clients and access tokens tables:

php artisan migrate

And then run the below command.

php artisan passport:install

5. Add API Driver in Guards in auth.php

We need to add API driver in guards, just go to the config/auth.php and update the following code in guards.

'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'passport',
            'provider' => 'users',            
        ],
    ],

6. Add HasApiTokens Traits in User Model

Simply add the following code in your user model here \app\Models\User.php

<?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 HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
}

7. Create and Update LoginRegister Controller

In this step, we will create Login and Register Controller. Simply run the below command in your terminal window.

php artisan make:controller Auth\LoginRegisterController

Then, just go to the \Http\Controllers\Auth\LoginRegisterController.php and copy paste the following code in it.

<?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Validator;

class LoginRegisterController extends Controller
{
     /**
     * Register a new user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $validate = Validator::make($request->all(), [
            'name' => 'required|string|max:250',
            'email' => 'required|string|email:rfc,dns|max:250|unique:users,email',
            'password' => 'required|string|min:8|confirmed'
        ]);

        if($validate->fails()){
            return response()->json([
                'status' => 'failed',
                'message' => 'Validation Error!',
                'data' => $validate->errors(),
            ], 403);
        }

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password)
        ]);

        $data['token'] = $user->createToken($request->email)->accessToken;
        $data['user'] = $user;

        $response = [
            'status' => 'success',
            'message' => 'User is created successfully.',
            'data' => $data,
        ];

        return response()->json($response, 201);
    }

    /**
     * Authenticate the user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function login(Request $request)
    {
        $validate = Validator::make($request->all(), [
            'email' => 'required|string|email',
            'password' => 'required|string'
        ]);

        if($validate->fails()){
            return response()->json([
                'status' => 'failed',
                'message' => 'Validation Error!',
                'data' => $validate->errors(),
            ], 403);  
        }

        // Check email exist
        $user = User::where('email', $request->email)->first();

        // Check password
        if(!$user || !Hash::check($request->password, $user->password)) {
            return response()->json([
                'status' => 'failed',
                'message' => 'Invalid credentials'
                ], 401);
        }

        $data['token'] = $user->createToken($request->email)->accessToken;
        $data['user'] = $user;
        
        $response = [
            'status' => 'success',
            'message' => 'User is logged in successfully.',
            'data' => $data,
        ];

        return response()->json($response, 200);
    } 

    /**
     * Log out the user from application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function logout(Request $request)
    {
        auth()->user()->tokens()->delete();
        return response()->json([
            'status' => 'success',
            'message' => 'User is logged out successfully'
            ], 200);
    }    
}

8. Create and Update Product Model with Migration and Model API Resource Controller

In the step 6, first we need to create product model with migration and model API resource controller, we have options either we can create each of these files individually or we can also create all of them together.

Simply run the below command in your terminal to create all these files.

php artisan make:model Product -mcr --api

After that, just go to \database\migrations directory and locate your product migration file with name like YYYY_MM_DD_TIMESTAMP_create_products_table.php, open this file and update the following code in it.

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->timestamps();
        });
    }

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

After migration code, now we need to update the product model code, just go to the \app\Models\Product.php and update the following code in it.

<?php

namespace App\Models;

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

class Product extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'description'
    ];
}

In the last, we need to go to the product controller \app\Http\Controllers\ProductController.php and update the following code in it.

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;
use Validator;

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $products = Product::latest()->get();
        
        if (is_null($products->first())) {
            return response()->json([
                'status' => 'failed',
                'message' => 'No product found!',
            ], 200);
        }

        $response = [
            'status' => 'success',
            'message' => 'Products are retrieved successfully.',
            'data' => $products,
        ];

        return response()->json($response, 200);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $validate = Validator::make($request->all(), [
            'name' => 'required|string|max:250',
            'description' => 'required|string|'
        ]);

        if($validate->fails()){  
            return response()->json([
                'status' => 'failed',
                'message' => 'Validation Error!',
                'data' => $validate->errors(),
            ], 403);    
        }

        $product = Product::create($request->all());

        $response = [
            'status' => 'success',
            'message' => 'Product is added successfully.',
            'data' => $product,
        ];

        return response()->json($response, 200);
    }

    /**
     * Display the specified resource.
     */
    public function show($id)
    {
        $product = Product::find($id);
  
        if (is_null($product)) {
            return response()->json([
                'status' => 'failed',
                'message' => 'Product is not found!',
            ], 200);
        }

        $response = [
            'status' => 'success',
            'message' => 'Product is retrieved successfully.',
            'data' => $product,
        ];
        
        return response()->json($response, 200);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, $id)
    {
        $validate = Validator::make($request->all(), [
            'name' => 'required',
            'description' => 'required'
        ]);

        if($validate->fails()){  
            return response()->json([
                'status' => 'failed',
                'message' => 'Validation Error!',
                'data' => $validate->errors(),
            ], 403);
        }

        $product = Product::find($id);

        if (is_null($product)) {
            return response()->json([
                'status' => 'failed',
                'message' => 'Product is not found!',
            ], 200);
        }

        $product->update($request->all());
        
        $response = [
            'status' => 'success',
            'message' => 'Product is updated successfully.',
            'data' => $product,
        ];

        return response()->json($response, 200);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id)
    {
        $product = Product::find($id);
  
        if (is_null($product)) {
            return response()->json([
                'status' => 'failed',
                'message' => 'Product is not found!',
            ], 200);
        }

        Product::destroy($id);
        return response()->json([
            'status' => 'success',
            'message' => 'Product is deleted successfully.'
            ], 200);
    }

    /**
     * Search by a product name
     *
     * @param  str  $name
     * @return \Illuminate\Http\Response
     */
    public function search($name)
    {
        $products = Product::where('name', 'like', '%'.$name.'%')
            ->latest()->get();

        if (is_null($products->first())) {
            return response()->json([
                'status' => 'failed',
                'message' => 'No product found!',
            ], 200);
        }

        $response = [
            'status' => 'success',
            'message' => 'Products are retrieved successfully.',
            'data' => $products,
        ];

        return response()->json($response, 200);
    }
}

9. Define API Endpoints in routes/api.php

Finally, we need to define all the API routes / endpoints for the user registration, login and log out, and also product CRUD routes with search products route.

Simply update the following code in \routes\api.php

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\Auth\LoginRegisterController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/

// Public routes of authtication
Route::controller(LoginRegisterController::class)->group(function() {
    Route::post('/register', 'register');
    Route::post('/login', 'login');
});

// Public routes of product
Route::controller(ProductController::class)->group(function() {
    Route::get('/products', 'index');
    Route::get('/products/{id}', 'show');
    Route::get('/products/search/{name}', 'search');
});

// Protected routes of product and logout
Route::middleware('auth:api')->group( function () {
    Route::post('/logout', [LoginRegisterController::class, 'logout']);

    Route::controller(ProductController::class)->group(function() {
        Route::post('/products', 'store');
        Route::post('/products/{id}', 'update');
        Route::delete('/products/{id}', 'destroy');
    });
});

10. Migrate Product Table to Database

Now, we have reach towards the final step which is migration of our product table in database. Just run the below command on your terminal to migrate product migration table in your database.

php artisan migrate

11. Run Laravel Development Server & Test the Application

Now, we have completed our application, we can start the Laravel development server and test our Laravel 10 REST APIs with Passport authentication.

Run the below command to start server.

php artisan serve

After that open the Postman application to test our APIs, make sure that you already installed Postman, it is an application that helps to test our APIs.

if you do not have Postman account then first you will need to install Postman into your machine and then create your Postman account and login with your credentials.

Now on the Postman application go to the top left, there is a New button to create new API request. Click on New button and then select the HTTP from the given options.

Additionally, keep in mind that you add the Accept => application/json in the Header of all APIs requests. Screenshot is given below for your understanding.

Postman Header Accept JSON

End Points / Routes of API:

Register and Login Routes:

1) User Registration API URL: http://127.0.0.1:8000/api/register

Method: POST

Registration is a public route, just enter required fields data then press Send button to get the response from user registration API. You will get a response in the body section of your request just like below screenshot.

Rest API User Registration with Passport

In the “data” -> “token” is returned which we will need to pass to access the protected routes.

Once user is registered, you can login the user with user credentials on the login route.

2) User Login API URL: http://127.0.0.1:8000/api/login

Method: POST

Login is also a public route, just enter required fields data then press Send button to get the response from the user login API. You will get response like below screenshot.

Rest API User Login with Passport

Login API also returns the “token” in data, we can use this token to access product protected route to create, update and delete a product.

You will need to pass the token with each protected routes in the Authorization -> Type -> Bearer Token in Token field same like in below screenshot.

Add Bearer Token in Authorization

Product CRUD Application and Logout Routes:

3) Create Product API URL: http://127.0.0.1:8000/api/products

Method: POST

Create product is a protected route, pass token and enter required fields data then press Send button, you will a response like below screenshot.

Add Product API Using Passport Token

4) Show All Products API URL: http://127.0.0.1:8000/api/products

Method: GET

This is a public route, just press a Send button and you will get the response like below screenshot.

Show All Products API

5) Show Single Product API URL: http://127.0.0.1:8000/api/products/{id}

Method: GET

This is a public route, pass the product ID in URL and press a Send button and get the response like below screenshot.

Show Single Product API

6) Update Product API URL: http://127.0.0.1:8000/api/products/{id}

Method: POST

This is a protected route, just add token, pass the product ID in URL and enter required fields data then press a Send button and you will get the response like below screenshot.

Update Product API

7) Search Products API URL: http://127.0.0.1:8000/api/products/search/{name}

Method: GET

This is also a public route, just pass the search keyword in URL and press a Send button and get the response like below screenshot.

Search Products API

8) Delete Product API URL: http://127.0.0.1:8000/api/products/{id}

Method: DELETE

This is a protected route, simply add access token, pass the product ID in URL and press a Send button and then you will get the response same like below screenshot.

Delete Product API

9) Logout User API URL: http://127.0.0.1:8000/api/logout

Method: POST

This is also a protected route, just add token and press a Send button and you will get response like below screenshot.

Logout User API

Conclusion

In the end of this tutorial, we hope that you have learnt how to create a Laravel 10 REST API using Passport authentication application by following the above step by step guide.

If you found this tutorial helpful, share it with your friends and developers group.

We spent several hours to create this tutorial, if you want to say thanks so like our page on Facebook, Twitter and share it.

Download

Facebook Official Page: All PHP Tricks

Twitter Official Page: All PHP Tricks

Article By
Javed Ur Rehman is a passionate blogger and web developer, he loves to share web development tutorials and blogging tips. He usually writes about HTML, CSS, JavaScript, Jquery, Ajax, PHP and MySQL.
  1. This tutorial helped me a lot, I was able to register, log in, and obtain the data. but now I don’t know how to do it, for example, show the list of products on another domain. If you could make another one explaining how to consume the api from another site it would be great, thank you

Leave a Reply

Your email address will not be published. Required fields are marked *