Laravel 8 API authentication using Passport from the scratch

Laravel provides 2 ways API authentication using API tokens. Laravel Sanctum is useful for single page application, mobile application or small application. However it doesn't support OAuth2, so if you want your application authentication using OAuth2, Laravel Passport is the best option for Laravel 8 application.

In this tutorial article, we will set Laravel Passport authentication into Laravel 8 application. We will do it from the scratch. Below are the steps we will follow in this tutorial.

  • Step 1: Create fresh Laravel application
  • Step 2: Configure MySQL database
  • Step 3: Install Passport package
  • Step 4: Configure Passport into application
  • Step 5: Create controller for authentication
  • Step 6: Create authentication routes
  • Step 7: Test application using Postman

So, let's start from creating new Laravel 8 application.

Step 1: Create fresh Laravel application

Of course first step is to create a fresh Laravel application. We will create application using composer command. You can install Composer with following this article. Open the Terminal or CMD and run the following command from the directory where you want to create Laravel application.

composer create-project laravel/laravel passport

After the application is created, next is to change directory using cd command.

cd passport

Step 2: Configure MySQL database

We will configure MySQL database into .env file. All issued token are stored into database. So open .env file and change the database credentials according to your MySQL.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=passport
DB_USERNAME=root
DB_PASSWORD=secret

Step 3: Install Passport package

In the third step, we will install Laravel Passport. Laravel Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp.

Run the below composer command to install Passport package.

composer require laravel/passport

Now run the migrate command to create tables into database. Passport's service provider also creates its own database table. So you should always migrate your database after installing this package. 

php artisan migrate

Now we needed to run passport:install artisan command. This will create encryption keys needed to generate secure access tokens.

php artisan passport:install

Step 4: Configure Passport into application

After the Passport installed, next step is to configure into Laravel application. You need to add few lines into application files. First open the model which you want to use for authentication. We will use Laravel's default User model to authenticate. In the model, add Laravel\Passport\HasApiTokens trait.

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

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

Note: User model already use Laravel\Sanctum\HasApiTokens trait, so you need to change it to Laravel\Passport\HasApiTokens. Or you may set alias using as keyword. 

Now, you need to add Laravel\Passport\Passport::routes() method into the boot method of your App\Providers\AuthServiceProvider.

<?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();

        if (! $this->app->routesAreCached()) {
            Passport::routes();
        }
    }
}

Add the Passport's api guard into config/auth.php. So, open config/auth.php file and add api guard as below:

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

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

Finally, run passport:keys command into Terminal to generates the encryption keys Passport needs in order to generate access tokens.

php artisan passport:keys

Step 5: Create controller for authentication

We have integrated Laravel Passport. Now we need controller to authenticate users .This will issue and use Passport tokens. Run the following artisan command to create controller class.

php artisan make:controller PassportController

This will create controller class at app/Http/Controllers/PassportController.php file. Open the file and add below methods into it.

<?php

namespace App\Http\Controllers;

use Validator;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\TokenRepository;
use Laravel\Passport\RefreshTokenRepository;

class PassportController extends Controller
{
    /**
     * Register user.
     *
     * @return json
     */
    public function register(Request $request)
    {
        $input = $request->only(['name', 'email', 'password']);

        $validate_data = [
            'name' => 'required|string|min:4',
            'email' => 'required|email',
            'password' => 'required|min:8',
        ];

        $validator = Validator::make($input, $validate_data);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Please see errors parameter for all errors.',
                'errors' => $validator->errors()
            ]);
        }
 
        $user = User::create([
            'name' => $input['name'],
            'email' => $input['email'],
            'password' => Hash::make($input['password'])
        ]);
         
        return response()->json([
            'success' => true,
            'message' => 'User registered succesfully, Use Login method to receive token.'
        ], 200);
    }
 
    /**
     * Login user.
     *
     * @return json
     */
    public function login(Request $request)
    {
        $input = $request->only(['email', 'password']);

        $validate_data = [
            'email' => 'required|email',
            'password' => 'required|min:8',
        ];

        $validator = Validator::make($input, $validate_data);
        
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Please see errors parameter for all errors.',
                'errors' => $validator->errors()
            ]);
        }

        // authentication attempt
        if (auth()->attempt($input)) {
            $token = auth()->user()->createToken('passport_token')->accessToken;
            
            return response()->json([
                'success' => true,
                'message' => 'User login succesfully, Use token to authenticate.',
                'token' => $token
            ], 200);
        } else {
            return response()->json([
                'success' => false,
                'message' => 'User authentication failed.'
            ], 401);
        }
    }

    /**
     * Access method to authenticate.
     *
     * @return json
     */
    public function userDetail()
    {
        return response()->json([
            'success' => true,
            'message' => 'Data fetched successfully.',
            'data' => auth()->user()
        ], 200);
    }

    /**
     * Logout user.
     *
     * @return json
     */
    public function logout()
    {
        $access_token = auth()->user()->token();

        // logout from only current device
        $tokenRepository = app(TokenRepository::class);
        $tokenRepository->revokeAccessToken($access_token->id);

        // use this method to logout from all devices
        // $refreshTokenRepository = app(RefreshTokenRepository::class);
        // $refreshTokenRepository->revokeRefreshTokensByAccessTokenId($$access_token->id);

        return response()->json([
            'success' => true,
            'message' => 'User logout successfully.'
        ], 200);
    }
}

Step 6: Create authentication routes

We have created controller class and methods. Now we need routes to handle these methods. API routes are located at routes/api.php file. So open this file and add following routes.

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PassportController;

Route::post('register', [PassportController::class, 'register']);
Route::post('login', [PassportController::class, 'login']);

// put all api protected routes here
Route::middleware('auth:api')->group(function () {
    Route::post('user-detail', [PassportController::class, 'userDetail']);
    Route::post('logout', [PassportController::class, 'logout']);
});

Step 7: Test application using Postman

We have completed the application coding part. Now we need to test API. For that we will use Postman application. We will test register, login, fetch user details with authentication and logout.

First of all, start Laravel server using following artisan command.

php artisan serve

Test application

In the application, if your request data is correct, you will get success parameter with true. If there is error, success response is false along with errors parameter response all errors. All the routes in routes/api.php are prefixed with api.

Register user

In the Postman, use http://localhost:8000/api/register post url, with data as below screenshot. If the success parameter in response is true, that means, the user is successfully registered.

Login user

Now we need access token, which will be used to access all authentication protected routes. To get token, we use login method. In the Postman, use http://localhost:8000/api/login url with email and password data. If the credentials is right, you will get token parameter with access token.

Get User details.

We have get the access token. Save this token to anywhere in your frontend application. In the authentication protected routes, we need to pass this token in the header.

Accept: application/json
Authorization: Bearer eqyJ0eX...............8_lZKM

If you pass wrong token or omit this header, the application response Unauthenticated message.

Logout user

When user run logout route, we revoke the token and expire it. You can logout user from the current device or from the all device. Logging out user from all devices will revoke all issued token fot that user.

Conclusion

So in this tutorial article, we have implemented API registration, login, access protected routes and logout. You can find more customization details for Passport at official documentation. I hope this tutorial will help you on building awesome application. Happy coding.