15 1 0 4000 1 https://codeblock.co.za 300 true 0
Authenticate and Safeguard Your Laravel API With Sanctum

Authenticate and Safeguard Your Laravel API With Sanctum

0 Comments

Laravel makes it super simple to create and deploy an API for use on other platforms, whether it be a web or mobile app. However, is some circumstances, we may not want that information readily available for unauthorised users or even bots. Thankfully, Laravel provides us with Sanctum, a featherweight authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs.

Prerequisites

  • A basic Laravel project installed.
  • Postman for testing GET, POST, PUT and DELETE requests.

For the example in this post, let’s imagine we have an API that keeps a record of all our customers. Obviously, only the employees of our organisation should have access to this information, so they must be logged in to gain access. When you create a Laravel application, by default, that information is accessible anywhere on the Internet. Sanctum works as any Laravel middleware would, giving you the ability to authenticate any routes you don’t want to make accessible without the proper permissions. In the case of Laravel Sanctum, permission is granted by means of a valid token which the user will receive upon providing the correct credentials, ie, an email address and password.

Creating the Customers Controller and Route

Create a Model and Migration

If you haven’t already, make sure to create the Customer model and migration, adding whichever columns to the customers table you need. For this example, I’ve only added a first name, last name and email address. You can quickly create a model and migration using the Artisan command $ php artisan make:model Customer -m.

Add the columns to the migration.

<?php

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

class CreateCustomersTable extends Migration
{
   public function up()
   {
       Schema::create('customers', function (Blueprint $table) {
          $table->id();
          $table->string('firstname');
          $table->string('lastname');
          $table->string('email');
       });
   }

   ...
}

Next, you’ll need to run the migration using $ php artisan migrate.

You should set up the customer model. Because my table has no timestamps, I’ll need to make sure to exclude timestamps in the model, but if you chose leave the default timestamps columns, you won’t need to.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    //table name
    protected $table = 'customers';

    //primary key
    public $primaryKey = 'id';

    // Timestamps
    public $timestamps = false;

    // Make all inputs mass-assignable
    protected $guarded = [];
}

Create the Customers Controller

This controller has an index method that will simply return all our customers in json format. This is a simple query, if you want, you could add ordering and limiting the response for pagination if need be.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Customer;

class InvoicesController extends Controller
{
   public function index()
   {
      $customers = Customer::all();
      return response()->json($customers, 200);
   }
}

Add the Route

In the routes folder in the project directory is a file named api.php. This file will create routes to our controller methods. Since our controller method is called index, we’ll need a route that looks like the one below. Notice we don’t have to add “api” to the route path since Laravel appends “/api” to the root domain.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

...

Route::get('customers', 'CustomersController@index');

Add a Few Customers to the Database

Just so there’s some data to work with, you should add a couple of customers to the newly created customers table. You can either do this manually or by creating a database seeder. Your choice.

Test the API Route

As it stands right now, if you visit https://yourdomain.com/api/customers, you’ll get a json response with all the data. I like to use Postman for this sort of thing. The reponse data should look something like this:

[
{"id":1,"firstname":"Anthony","lastname":"Stark","email": "ironman@starkindustries.com" },
{"id":2,"firstname":"Steve","lastname":"Rogers","email": "elcapitano@shield.us"},
]

But this route is unauthenticated and that’s a problem since we don’t want any old Tom, Dick and Harry to access this data. Now we have to install Sanctum and setup the middleware.

Install and Set Up Laravel Sanctum Middleware

Install Sanctum

To install Laravel Sanctum, simply run the Artisan artisan command
$ composer require laravel/sanctum.

Once Sanctum is installed, you’ll need to publish the config file:
$ php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Sanctum will create a new database migration called _create_personal_access_tokens_table, so you’ll need to run your migrations again:
$ php artisan migrate

Add Sanctum Middleware

With Sanctum installed, we need to let Laravel know to use it. We need to import the EnsureFrontendRequestsAreStateful class into Kernel.php and add it to the api array in $middlewareGroups:
EnsureFrontendRequestsAreStateful::class,
like so:

<?php

namespace App\Http;
// Import EnsureFrontendRequestsAreStateful
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
   
    protected $middleware = [
       ...
    ];

  
    protected $middlewareGroups = [
        'web' => [
           ...
        ],

        'api' => [
            // include EnsureFrontendRequestsAreStateful is middleware group
            EnsureFrontendRequestsAreStateful::class,
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

    
    protected $routeMiddleware = [
       ...
    ];
}

Assign Tokens and Allow Access to Authenticated Users

With Sanctum setup, we now need to manage user access. Let’s start with the User model. Laravel already has a User model, so let’s edit it.

First we need to import HasApiTokens into the User model, then we need to include the trait in the User class like so.

<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

// Import HasApiTokens

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    // use HasApiTokens
    use Notifiable, HasApiTokens
    protected $fillable = [
        'name', 'email', 'password',
    ];

    ....
}

Create a UsersController and Login Method

The login method will be in charge of issuing a hashed SHA-256 token to the user which will give them access to the data we’re protecting. In the case of a Single Page Application (SPA) or mobile application, you may instead save this token in the user’s browser or device to query it later on, however we won’t be getting into that in this tutorial.

To create a the Users Controller we can create it manually or run
$ php artisan make:controller UsersController

Next, we need to add the login method like so:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
// Import the User Model
use App\User;
// Import Hash so we can verify the password
use Illuminate\Support\Facades\Hash;

class UsersController extends Controller
{   
    public function login(Request $request)
    {
        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            return response([
                'message' => ['Please submit a valid email address and password combination.']
            ], 404);
        }
    
        $token = $user->createToken('user-token')->plainTextToken;
    
        $response = [
            'user' => $user,
            'token' => $token
        ];
    
        return response($response, 201);
    }

}

When the login method above is called, it will check for a user matching the submitted email address. If no user is found, it will return the failure message and if a user is found, it will check that the password, once hashed, matches the user’s password. If it doesn’t, it will fail.

Once the user’s credentials are in order, Sanctum will assign them a new plain-text token. After that we send a response back to the user with their information and this newly generated token.

At this point, you could show the user the token or save it in the browser or app. You may have used or seen apps that allow users to use their API with a special token that was generated. This works exactly like that.

We need to add a route before the user can access the login method.

Create a Login Route and a Sanctum Middleware Group

The login route must be open and unauthenticated. Remember, a user will not be authenticated when trying to login or get a token, so to do this, we need to add the following route to our API routes.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

...

// The login route must not require authentication
Route::post('login', 'UsersController@login');

Route::get('customers', 'CustomersController@index');

The action that the form the user will use to log in should now submit to https://yourdomain.com/api/login using the POST method.

Guard All Authenticated API Routes With Laravel Sanctum Middleware Group

Finally, now that Sanctum is set up and can issue the user a token, we can block access to any routes that require authentication using Laravel’s middleware group feature and the new middleware, auth:sanctum.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

...

// The login route must not require authentication and any routes that don't require authentication should be placed outside the middleware group
Route::post('login', 'UsersController@login');

Route::group(['middleware' => 'auth:sanctum'], function() {

    // All routes that require authentication must be placed in this code block
    Route::get('customers', 'CustomersController@index');
    
});

If you go back to Postman and try visiting https://yourdomain.com/api/customers, it will get you a 404 not found response. To test that your authentication is working, first visit https://yourdomain.com/api/login and make sure to include Content-type application/json the header. You should receive a response with the token. Copy the token then go back to https://yourdomain.com/api/customers but this time make sure to add your token to the Bearer Token header and you’ll get your customers.

Conclusion

Adding authentication to your Laravel API is simple and quick. You can set up the whole process in less than 10 minutes allowing you to manage both your authenticated and unauthenticated routes in an organised manner.

Is this still valid in 2021? Please let me know in the comments below.

Was This Helpful?

Create a Custom Alert and Confirmation Dialogue With PHP and JQuery
Previous Post
Create a Custom Alert and Confirmation Dialogue With PHP and JQuery
Create a Lightbox Photo Gallery With JQuery
Next Post
Create a Lightbox Photo Gallery With JQuery

0 Comments

Leave a Reply