How to secure Laravel API
Published: 2022-01-31 11:33:41

Laravel Passport provides a full OAuth2 server implementation for your laravel application. If your application needs to support OAuth2, then you should use Laravel Passport.
To get started, install Passport via the Composer package manager as follows;
```
composer require laravel/passport
```

Passport has its service provider that registers its own database migration directory, so you should migrate your database after installing the package. The Passport migrations will create the tables your application needs to store OAuth2 clients and access tokens:
```
php artisan migrate
```
Next, execute the following artisan command;
```
php artisan passport:install
```
The above command creates the encryption keys needed to generate secure access tokens. This also creates "personal access" and "password grant" clients which will be used to generate access tokens.

After running the passport:install command, add <b>Laravel\Passport\HasApiTokens</b> trait to your model that authenticates your users. In my case, I use customer model as the authentication model.
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
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 Customer extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    protected $table = "customers";
    public $timestamps = true;

    protected $guarded=['id'];
    protected $fillable = [
       'first_name',
       'last_name',
       'phone_number',
       'email',
       'account_balance',
       'password'
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function getAuthPassword(){
        return $this->password;
    }

}
```
As you can see in the above code snippet, my model Customer uses HasApiTokens trait.

The next step is to call the <b>Passport::routes</b> method within the boot method of your <b>App\Providers\AuthServiceProvider</b>. This method registers the routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens.
```php
<?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();
         
         // scope customer used when creating access token  
         Passport::tokensCan([
            'customer' => 'Customer access',
         ]);


    }
}
```
In the next step, in the application's <b>config/auth.php</b>, I set the driver option of my customized api authentication guard called <b>api-customers</b> to passport. This instructs the application to use passport's TokenGuard when authenticating incoming customer API requests.
```php
   'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api-customers' => [
            'driver' => 'passport',
            'provider' => 'customers',
            'hash' => false,
        ],
    ],

```
in the above config/auth.php file, I have created an authentication guard called <b>api-customers</b> which uses provider customers. Below is my provider <b>customers</b> set in the providers array in the same file.
```php
  'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

         'customers' => [
            'driver' => 'eloquent',
            'model' => App\Models\Customer::class,
        ],

    ],
```
Lastly, you can apply auth middleware to your routes in routes/api.php as seen in the example below;
```php
Route::group(['prefix' => 'customer', 'middleware' => ['auth:api-customers']], function(){
 Route::get('/search/{id}', [CustomerController::class, 'findCustomer']);
});
```
In the above route for searching customer, an auth middleware on the customer guard(<b>api-customers</b>) is used and any request to this endpoint will be authenticated using Laravel passport since we applied it to the api authentication guard called api-customers.

Now users will be assigned new access tokens every time they login. Access token in the login method in your login controller can be created as follows;
```php
$access_token = $customer->createToken('Customer'.$customer->phone_number, ['customer'])->accessToken;
```
This token must be sent as part of headers in the http requests from the frontend to the API if the end point is to be accessed.

And that's how you can secure your application or your laravel api end points using Laravel Passport. Thank you for reading through this, see you in my next post.