Laravel Passport – Create REST API with authentication

1 1,934

In this tutorial, we will see how to use laravel passport authentication in your Laravel application. We will also build a simple Product CRUD (Create, Read, Update and Delete) using Laravel Passport Authentication.

Laravel already provides tradition login forms authentication, but what if you want to use APIs? APIs use tokens for authenticating users, because they do not use sessions. When a user login via API, a token is generated and sent to the user which is used for authentication purposes. Laravel provides Passport to work with API Authentication without any difficulty.

Let’s see how to setup and configure Laravel Passport for API Authentication and RESTful APIs in a Laravel application.

Creating a new project

Let’s start by creating a new Laravel project. Run the following command to create a new project.

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

Install Package

We need to install Laravel Passport package via the composer dependency manager. Run the following command to require the package.

composer require laravel/passport

Adding Laravel Passport

Laravel Passport requires some steps to set up properly.

Service Provider

I am using Laravel 5.6 which is the latest version of laravel right now which automatically registers package using package auto discovery. If you are using laravel 5.4 or below, you need to add Service Provider in the config/app.php file. So, open the file and add the Service Provider in the providers array.

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

Migration and Installation

Setup database credentials in .env file. Laravel Passport comes up with migration for passport tables that are required to be in our database. Passport Migrations are used for storing tokens and client information. Run migration command to migrate schemas to your database.

php artisan migrate

Next, it is required to install passport using the command below. It will generate encryption keys required to generate secret access tokens.

php artisan passport:install

Passport Configure

In this step, we need to make changes in our Laravel application to complete passport configuration.

app/User.php

Add Laravel\Passport\HasApiTokens trait to your User model. It will provide few helper methods.

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, 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',
    ];
}

AuthServiceProvider

Add Passport::routes method in the boot method of your AuthServiceProvider. It will generate necessary routes. This is how the app/Providers/AuthServiceProvider.php will look like after changes.

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;

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

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

        Passport::routes();
    }
}

config/auth.php

In the config/auth.php file, set driver to the passport.

return [
    ....

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

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],

    ....
]

Create Route

Let’s create API routes. Add routes in the routes/api.php file.

Route::post('login', 'PassportController@login');
Route::post('register', 'PassportController@register');

Route::middleware('auth:api')->group(function () {
    Route::get('user', 'PassportController@details');

    Route::resource('products', 'ProductController');
});

Create Controller for Authentication

Let’s set up our logic for Authentication. Create Passport Controller by running the following command.

php artisan make:controller PassportController

Copy the contents below to app/Http/Controllers/PassportController.php

<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;

class PassportController extends Controller
{
    /**
     * Handles Registration Request
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|min:3',
            'email' => 'required|email|unique:users',
            'password' => 'required|min:6',
        ]);

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

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

        return response()->json(['token' => $token], 200);
    }

    /**
     * Handles Login Request
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $credentials = [
            'email' => $request->email,
            'password' => $request->password
        ];

        if (auth()->attempt($credentials)) {
            $token = auth()->user()->createToken('TutsForWeb')->accessToken;
            return response()->json(['token' => $token], 200);
        } else {
            return response()->json(['error' => 'UnAuthorised'], 401);
        }
    }

    /**
     * Returns Authenticated User Details
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function details()
    {
        return response()->json(['user' => auth()->user()], 200);
    }
}

Let me explain what’s happening in the code above

In the register method, we validate the request data and then create the user. We then create the token using the createToken method and passing the name as an argument. Finally, we return token in a JSON response.

In the login method, we attempt to authenticate using the request details. Then, we return an appropriate response based on the success or failure of the attempt.

In the details method, we simply return the user eloquent model.

Create Product CRUD

Let’s create a product CRUD. Run the following command to create Product Model, Migration and Controller.

php artisan make:model Product -mc

It will create a new database migration file create_products_table.php in database/migrations directory. Update the up method to the code below.

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->string('name');
        $table->integer('price');
        $table->timestamps();

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

Now, add a fillable property to the Product model. Open the Product.php file in the app directory.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [
        'name', 'price'
    ];
}

Now, run database migration.

php artisan migrate

Now, let’s add a product relationship method in the app/User.php file.

public function products()
{
    return $this->hasMany(Product::class);
}

Open the ProductController.php file in app/Http/Controllers directory. Copy the contents below to the Product Controller.

<?php

namespace App\Http\Controllers;

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

class ProductController extends Controller
{
    public function index()
    {
        $products = auth()->user()->products;

        return response()->json([
            'success' => true,
            'data' => $products
        ]);
    }

    public function show($id)
    {
        $product = auth()->user()->products()->find($id);

        if (!$product) {
            return response()->json([
                'success' => false,
                'message' => 'Product with id ' . $id . ' not found'
            ], 400);
        }

        return response()->json([
            'success' => true,
            'data' => $product->toArray()
        ], 400);
    }

    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'price' => 'required|integer'
        ]);

        $product = new Product();
        $product->name = $request->name;
        $product->price = $request->price;

        if (auth()->user()->products()->save($product))
            return response()->json([
                'success' => true,
                'data' => $product->toArray()
            ]);
        else
            return response()->json([
                'success' => false,
                'message' => 'Product could not be added'
            ], 500);
    }

    public function update(Request $request, $id)
    {
        $product = auth()->user()->products()->find($id);

        if (!$product) {
            return response()->json([
                'success' => false,
                'message' => 'Product with id ' . $id . ' not found'
            ], 400);
        }

        $updated = $product->fill($request->all())->save();

        if ($updated)
            return response()->json([
                'success' => true
            ]);
        else
            return response()->json([
                'success' => false,
                'message' => 'Product could not be updated'
            ], 500);
    }

    public function destroy($id)
    {
        $product = auth()->user()->products()->find($id);

        if (!$product) {
            return response()->json([
                'success' => false,
                'message' => 'Product with id ' . $id . ' not found'
            ], 400);
        }

        if ($product->delete()) {
            return response()->json([
                'success' => true
            ]);
        } else {
            return response()->json([
                'success' => false,
                'message' => 'Product could not be deleted'
            ], 500);
        }
    }
}

Testing

Now, our logic is complete, let’s start testing. We will be testing it on PHP development server but you can use virtual host if you want. Run the following command to serve the application on the PHP development server.

php artisan serve

Now, let’s test our API endpoints using an API testing tool like Postman.

Register API

Laravel Passport Authentication Register

Login API

Laravel Passport Authentication Login

Details API

When testing Details API or any API that requires a user to be authenticated, you need to specify two headers. You must specify access token as a Bearer token in the Authorization header. Basically, you have to concatenate the access token that you received after login and registration with the Bearer followed by a space.

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

Laravel Passport Authentication Details

Products Index API

Passport Authentication Product Index

Product Store API

Passport Authentication Product store

Product Show API

Passport Authentication Product show

Product Update API

Passport Authentication Product update

Product Delete API

Passport Authentication Product delete

Full Source code for this tutorial is available at

Learn More
Restful API In Laravel 5.6 Using jwt Authentication

You might also like