Click Below to subscribe

How to Implement Sanctum Authentication in Laravel 2022

Laravel Sanctum provides a convenient way to setup authentication system for single page applications, mobile applications, and simple, token based APIs. 

In this article, we will implement sanctum authentication from scratch.

1. Let's create a new laravel project.

composer create-project laravel/laravel laravel-sanctum

2. After creating the project install the sanctum package.

composer require laravel/sanctum

Note:- Laravel 8+ versions by default comes with sanctum package installed so you don't need to install it.

3. Publish laravel sanctum config file.

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

This will create a sanctum.php file inside the config folder. this file contains all configurations of the sanctum. Here you can also set the lifetime(in minutes) of an access token.

sanctum.php

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/

'expiration' => null,

4. Update your database credentials in .env file.

DB_DATABASE=laravel-sanctum  // your database name
DB_USERNAME=root            // your database username 
DB_PASSWORD=               // your database password

5. Next we need to create personal_access_tokens table to store tokens. so publish the create_personal_access_tokens_table.php migration file.

php artisan vendor:publish --tag=sanctum-migrations

Note:- Laravel 8+ by default comes with xxxx_create_personal_access_tokens_table.php migration file so you don't need to publish it.

This command will generate xxxx_create_personal_access_tokens_table.php inside database/migrations directory.

6. Run migration

php artisan migrate

This command will migrate all migrations from database/migrations directory.

if you don't want to migrate all migration you can also only migrate create_personal_access_tokens_table.php

php artisan migrate  --path=your migration file path

php artisan migrate  --path=database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php

7. Update your User model.

go to app/Models and open User.php file. after that add Laravel\Sanctum\HasApiTokens  trait. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user's token and scopes.

Note:- Laravel 8+ by default has a Laravel\Sanctum\HasApiTokens trait. so you don't need to import it.

<?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\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

8. Create the AuthController.

php artisan make:controller Api/AuthController

Note:- Here Api is the folder name.

This will create AuthController.php inside app/Http/Controllers/Api directory

9. Update AuthController.php

<?php

namespace App\Http\Controllers\Api;

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

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email|unique:users',
            'password' => 'required'
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 400);
        }

        $user = new User();
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        return response()->json(['data' => $user]);
    }

    public function login(Request $request)
    {
        $credentials = $request->only(['email', 'password']);
        $validator = Validator::make($credentials, [
            'email' => 'required|email',
            'password' => 'required'
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 400);
        }

        if (!auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        /* ------------ Create a new personal access token for the user. ------------ */
        $token = auth()->user()->createToken('MyApiToken')->plainTextToken;

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

    public function getUser()
    {
        return response()->json(auth()->user());
    }

    public function logout()
    {
        /* --- Revoke the token that was used to authenticate the current request. -- */
        auth()->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Logged out successfully']);
    }
}

Note:- If you need to logout from all devices of a user.

// Revoke all tokens...
auth()->user()->tokens()->delete();

10. Go to app/Providers and open RouteServiceProvider.php. uncomment $namespace;

protected $namespace = 'App\\Http\\Controllers';

11. Go to app/Http/Middleware and open Authenticate.php. After that update redirectTo()  method.

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    protected function redirectTo($request)
    {
        if ($request->is('api/*')) {
            return route('unauthorized');
        }
        if (! $request->expectsJson()) {
            return route('login');
        }
    }
}

Note:- In the case of Unauthenticated(API) instead of redirecting to the login page we are redirecting to unauthorized route for the custom JSON response.

12. Go to routes folder and update api.php

<?php

use Illuminate\Support\Facades\Route;

Route::group(['prefix' => 'auth', 'namespace' => 'Api'], function () {

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

    Route::group(['middleware' => 'auth:sanctum'], function () {
        Route::get('logout',    'AuthController@logout');
        Route::get('user',      'AuthController@getUser');
    });

    Route::any('{segment}', function () {
        return response()->json(['error' => 'Bad request.'], 400);
    })->where('segment', '.*');
});

Route::get('unauthorized', function () {
    return response()->json(['error' => 'Unauthorized.'], 401);
})->name('unauthorized');

Finally Open Postman or any REST API Client and test these API's

Checkout my full laravel-sanctum example.

https://github.com/ultimateakash/laravel-sanctum

If you need any help, don't hesitate to comment below.

Thanks.

Leave Your Comment