Samson Omojola I'm an experienced software engineer. I love creating applications with responsive, beautiful, intuitive, state-of-the-art designs. I'm skilled in HTML, CSS, JavaScript, Ionic, React, PHP, Laravel, and Flutter.

Laravel Passport: A tutorial and example build

10 min read 3051

Introduction

Laravel Passport is an easy way to set up an authentication system for your API. As a Laravel package, it uses an OAuth2 server to perform authentication, creating tokens for user applications that request to interface with the API it protects, and only granting them access if their tokens are validated.

In this article, we will build an API that interacts with our database and processes the data of employees. The API will be secured using Passport, which will allow access to certain protected information only when an access token is provided.

Authentication in REST APIs

REST APIs have become the backbone of web platforms and data processing. This is because they encourage flexibility and scalability. With a REST API controlling the backend of an application, all kinds of client applications can interface with it, regardless of the language in which they are written. This way, a web app can service a wide variety of users.

One drawback of REST APIs is that they are stateless. In other words, application states are not kept on the server side. There are no sessions to keep track of states, like whether or not a user is logged in. One of the reasons for this is that asking the server to store the sessions of perhaps millions of users would overload it, thereby leading to performance bottlenecks and hindering scalability.

And so with REST APIs, it becomes the responsibility of the client application to store its own information and provide the server with all the information it needs every time a request is made. This constant state transfer is what the “ST” in “REST” stands for.

Rather than servers saving states and consuming lots of time and space, with REST APIs, client applications are provided with credentials to be sent to the server with each request. This credential is usually called an authorization token. The server validates this token, and then gives the client application access to the resources it requires. This process is called authentication.

Why is authentication important? APIs provide access to the information stored in your database – most likely sensitive information that you don’t necessarily want the general public to have access to. You need a way to verify that the user trying to access your information has permission. This is where authentication comes in.

What You’ll Build

By the end of this tutorial, you’ll have built a secure API that can be used to:

  • Register employees
  • Request a list of all employees
  • Request the details of a particular employee
  • Change the details of an employee
  • Delete the details of an employee

These are employee details to be saved in the database:

  • Name
  • Age
  • Job
  • Salary

Prerequisites

In order to follow along with this tutorial, you should have the following:

We made a custom demo for .
No really. Click here to check it out.

  • PHP, MySQL, and Apache installed. A simple installation of Xampp should take care of all these
  • Composer installed
  • Laravel installed, along with a basic understanding of this framework
  • Postman, to test the APIs we create

Step 1 – Creating a new Laravel application

There are two ways to scaffold a new application in Laravel. To use the Laravel installer, run:

laravel new application-name

To use composer instead, run:

composer create-project --prefer-dist laravel/laravel application-name

If you want to check out the boilerplate that comes with a newly created Laravel project, navigate into the directory of the project you just created and run:

php artisan serve

Open your web browser and enter the following url: http://localhost:8000

Now that we have an app up and running, we need to hook it up with a database. Create a database for your app and add the appropriate values for the following variables in your .env file:

DB_DATABASE
DB_USERNAME
DB_PASSWORD

With our database set up, we can proceed to setting up Passport in our application.

Step 2 – Installing and configuring Passport

Passport implements OAuth2 authentication in our app. It generates a unique token for every authenticated user, so every request sent to the API to access protected routes will be accompanied by this token. To install Passport with Composer, run the following command:

composer require laravel/passport

Passport will need to store OAuth2 clients and access tokens in some database tables, so it creates migrations for the tables during installation. Migrate your database to create the tables:

php artisan migrate

To generate secure access tokens for your application, Passport requires some encryption keys and two clients known as Laravel Personal Access Client and Laravel Password Grant Client. To create these keys and encryption clients, run the following command:

php artisan passport:install

To access certain protected routes in our application, our users will need to register and login. Not to worry, new Laravel applications come with a User model and users migration file out of the box. This will be sufficient for our needs.

You’ll need to inspect all authenticated users’ tokens and scopes. The HasApiTokens trait will provide you with some helper methods to carry this out. To add it to your User model, navigate to App\Models\User, add its namespace at the top, and specify for it to be used inside the User class:

<?php

namespace App\Models;

...
use Laravel\Passport\HasApiTokens;  //add the namespace

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;   //use it here
}

Passport comes with some routes used to issue and revoke access tokens. To register these routes, you need to call the Passport::routes method inside the boot method in your AuthServiceProvider. Navigate to App\Providers\AuthServiceProvider and update it.

In Laravel, Policies are used to protect resources from unauthorized access. Since some of our routes will need to be protected and will require access tokens to be accessed, we’ll be making use of Policies.

Inside the $policies array, comment this line: 'App\Models\Model' => 'App\Policies\ModelPolicy' to make it available for use:

<?php
namespace App\Providers;
use Laravel\Passport\Passport;  //import Passport here

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Models\Model' => 'App\Policies\ModelPolicy', //uncomment
    ];
    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();   //Register Passport routes
        //
    }
}

Your application needs to use Passport’s TokenGuard to authenticate incoming API requests. To set this up, navigate to your config/auth.php file, go to your api authentication guard, and set the value of the driver option to passport:

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

    'api' => [
        'driver' => 'passport', //update this line
        'provider' => 'users',
    ],
],

Step 3 – Creating a model and a migrations file for employees

To create a database to store our employees’ information, we’ll be creating an employee model and a migrations file using the below artisan command:

php artisan make:model Employee -m

The make:model command will create the new model inside your app folder. The -m flag will create the new migrations file inside your database/migrations folder.

Now, let’s proceed to creating our employees’ database table. Navigate to database/migrations, open your newly created create_employees_table file, and add the appropriate columns for all the employee information we’ll be storing (name, age, job, and salary):

<?php

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

class CreateEmployeesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('employees', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('age');
            $table->string('job');
            $table->string('salary');
            $table->timestamps();
        });
    }

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

Next, let’s align our Employee model with our migrations file above:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    protected $fillable = [
        'name', 'age', 'job', 'salary'
    ];
}

To create the table for which we just created the migrations file above, run the command below:

php artisan migrate

If you check your database now, you should see the employees table with all the fields we specified.

Step 4 – Creating our controllers

Before we create the controller that will handle employees details, let’s create the controller that will enable users be able to register, login, and use our application.

Use the command below to create it (we’ll call it UserAuthController and create a new folder for it called Auth):

php artisan make:controller Auth/UserAuthController

You can find the newly created controller in app/Http/Controllers/Auth. Let’s proceed to creating the register and login methods we need:

<?php

namespace App\Http\Controllers\Auth;

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

class UserAuthController extends Controller
{
    public function register(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|max:255',
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed'
        ]);

        $data['password'] = bcrypt($request->password);

        $user = User::create($data);

        $token = $user->createToken('API Token')->accessToken;

        return response([ 'user' => $user, 'token' => $token]);
    }

    public function login(Request $request)
    {
        $data = $request->validate([
            'email' => 'email|required',
            'password' => 'required'
        ]);

        if (!auth()->attempt($data)) {
            return response(['error_message' => 'Incorrect Details. 
            Please try again']);
        }

        $token = auth()->user()->createToken('API Token')->accessToken;

        return response(['user' => auth()->user(), 'token' => $token]);

    }
}

We now have a register method to create new users for our application.

Using Laravel’s validate()method, we ensure that the name field is filled and that the value entered into it does not exceed 255 characters. We also ensure that an email is entered for registration and that it is unique.

We use Laravel’s bcrypt function to hash the user’s password, as it is not safe to store their password as plain text. If all the registration requirements we’ve set are met, a new user account is created, an access token is generated, and the new user’s details, along with their user token, are returned back as response.

For the login method, we use Laravel’s validate() method again to ensure that both an email and a password are supplied. The auth()→attempt() method tries to login the user with the details they’ve provided. If the details are not the same as the ones with which they registered, an error message is displayed, asking them to try again. If the details are correct, an access token is created and the user is logged in – now ready to access our protected routes.

To access any protected route, the access token that was created will have to be passed along with the HTTP request, signaling to our application that the user is authorized to access private resources.

The controller that will process employee data will be returning responses in JSON format. Since we’ll mostly be returning model instances and collections of model instances, we can use Laravel Eloquent’s API Resources. If a user requests a list of employees, we can use resource to send the employee model back as response, in JSON format. If a user requests for the details of an employee, we can use resource to send that particular model instance back.

So let’s go ahead and create a Resource file for our Employee model:

php artisan make:resource EmployeeResource

Now if we need to send out employees details as response to an API call, we can use EmployeeResource to send them out in JSON format (in the form of an array). The advantage of this is that all kinds of client applications (Flutter, Angular, React etc.) can process JSON data easily.

The incoming HTTP requests our app will receive are going to be processed by a controller we will call the employee controller. The methods in this controller will return the appropriate responses to the HTTP requests in JSON format:

php artisan make:controller EmployeeController --api --model=Employee

The --api flag helps us create the five methods that are commonly used to perform operations on resources: index, store, show, update, and destroy. The --model flag signifies that the controller we are creating is for the Employee model and lets us use route model binding in the controller.

Now that we have a controller, let’s start creating the methods we need to process employee data. Navigate to your newly created controller app/Http/Controllers/EmployeeController.php and open it:

?php

namespace App\Http\Controllers;

use App\Models\Employee;
use App\Http\Controllers\Controller;
use App\Http\Resources\EmployeeResource;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class EmployeeController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $employees = Employee::all();
        return response([ 'employees' => 
        EmployeeResource::collection($employees), 
        'message' => 'Successful'], 200);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $data = $request->all();

        $validator = Validator::make($data, [
            'name' => 'required|max:50',
            'age' => 'required|max:50',
            'job' => 'required|max:50',
            'salary' => 'required|50'
        ]);

        if($validator->fails()){
            return response(['error' => $validator->errors(), 
            'Validation Error']);
        }

        $employee = Employee::create($data);

        return response([ 'employee' => new 
        EmployeeResource($employee), 
        'message' => 'Success'], 200);
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Employee  $employee
     * @return \Illuminate\Http\Response
     */
    public function show(Employee $employee)
    {
        return response([ 'employee' => new 
        EmployeeResource($employee), 'message' => 'Success'], 200);

    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Employee  $employee
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Employee $employee)
    {

        $employee->update($request->all());

        return response([ 'employee' => new 
        EmployeeResource($employee), 'message' => 'Success'], 200);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param \App\Employee $employee
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function destroy(Employee $employee)
    {
        $employee->delete();

        return response(['message' => 'Employee deleted']);
    }
}

The index method above gets the details of all the employees in our database and returns it in JSON format, using Resources. We use the store method to add the details of a new employee to the database. Using Laravel’s Validator, we ensure that information for all the columns in our employee table are provided. Then we return the details of the new employee in JSON format.

The show method fetches the details of a particular employee and returns it as JSON response. Here, we do not need to write code to query the database with a particular employee ID because we are making use of route model binding.

The update method is sent new information for an existing employee. It then updates the employee’s record in the database with this new information and returns the information back as response in JSON format. Just like with the show method, we do not need to write code to query the database with a particular employee ID, as we are making use of route model binding. It’s done automatically.

The destroy method simply deletes the details of an existing employee from the database and returns a success message.

Step 5 – Creating our routes

Next, let’s create the routes (endpoints) that will be responsible for responding to HTTP requests and redirecting them to the appropriate methods to process them and return a response. Navigate to routes/api.php and update it:

Route::post('/register', 'Auth\[email protected]');
Route::post('/login', 'Auth\[email protected]');

Route::apiResource('/employee', 'EmployeeController')->middleware('auth:api');

The first route above points to the register method we created inside our UserAuthController. Now, when this endpoint is called, our register method is triggered and a new user is created. The second route points to our login method, which is for logging in users.

The third route points to all the methods that will be responsible for processing employees’ data. Since our application is an API that simply provides endpoints to be called, we do not need routes and methods for HTML templates, like create and edit. By using the apiResource method above, we can exclude these two routes automatically and only create routes like index, store, show, update, and destroy. These 5 routes are represented by the apiResource method and they are pointing to the corresponding 5 methods in the Employee controller we created above.

We’ve used Passport to secure these routes by adding the auth:api middleware to them. Now, a valid access token will be required for any call made to any of these routes.

And we are done! To test your application, run the following command:

php artisan serve

I’ll be using Postman to test my API endpoints. You can use any software you are comfortable with.

Create new user

Our end point for creating a new user is http://localhost:8000/api/register. Using a POST request, supply a name, email, and password as shown below.

screenshot of new user data being entered

Login user

Now we can login the user we just created using this endpoint: http://localhost:8000/api/login.

screenshot of user successfully logging in

Add new employee

We can add a new employee to our database by sending their name, age, job, and salary to this endpoint: http://localhost:8000/api/employee.

Since this is a protected endpoint, be sure to copy the access token you were provided with when you logged in, click on the authorization tab in Postman, select Bearer Token on the Type dropdown list, and paste your token inside the Token field.

Screenshot of a new employee being added successfully

Get list of employees

You can get the list of employees from your database by using this endpoint: http://localhost:8000/api/employee. This time, we use a GET request.

Screenshot of a GET request

Get employee details

To get the details of a particular employee, we use the following endpoint: http://localhost:8000/api/employee/1. Here, “1” should be changed to the particular ID of the employee.

Screenshot of employee details being requested

Update employee details

To update the details of an employee, fill in the new details and send a PATCH request to http://localhost:8000/api/employee/1 (be sure to use the appropriate ID).

Screenshot of Postman

Delete an employee

To delete the details of an employee, send a DELETE request to http://localhost:8000/api/employee/1 (be sure to use the appropriate ID).

Screenshot of Postman deleting employee data

Conclusion

In 5 steps, we’ve created a REST API and secured it with Laravel Passport. To find out more about how to use Passport, you can check out the official documentation here. There’s also a Github repository for the project we built in this tutorial, in case you need it.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Samson Omojola I'm an experienced software engineer. I love creating applications with responsive, beautiful, intuitive, state-of-the-art designs. I'm skilled in HTML, CSS, JavaScript, Ionic, React, PHP, Laravel, and Flutter.

Leave a Reply