Build REST API with Laravel Passport

REST APIs are the backbone of modern web and mobile applications. While building a RESTful API with Laravel is straightforward, securing it is equally crucial. Laravel Passport offers a full OAuth2 server implementation for your Laravel application, enabling robust and standard methods of API authentication. In this article, we'll guide you through building a REST API with Passport, from installation to securing your endpoints.


Table of Contents

  1. Why Use Laravel Passport?
  2. Setting Up Laravel Passport
  3. Configuring Authentication Guards
  4. Building a Simple REST API
  5. Protecting Routes with Passport
  6. Testing the API
  7. Conclusion

Why Use Laravel Passport?

Passport provides a complete OAuth2 server for your app. Major reasons to choose Passport include:

  • OAuth2 Compliance: Standard and secure for third-party integrations.
  • First-party SPA Support: Easily issue tokens for your own frontend clients.
  • Refresh Tokens: Out-of-the-box support for token renewal.
  • User Scopes: Fine-grained access control by defining user abilities.

Setting Up Laravel Passport

Let's get started securing your API:

Prerequisites

  • Laravel 10+ installed
  • Composer
  • A configured database

1. Install Passport

composer require laravel/passport

2. Run Migrations

Passport requires several tables, like oauth_clients, oauth_access_tokens, etc.

php artisan migrate

3. Install Passport Assets

This command generates the encryption keys and clients required for issuing tokens.

php artisan passport:install

You’ll see something like:

Personal access client created successfully
Client ID: 1
Client secret: [secret]

Keep these credentials safe!

4. Add Passport Traits to User Model

Open app/Models/User.php:

namespace App\Models;

use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
    // ...
}

5. Register Passport Service Provider

Edit config/app.php (for Laravel < 5.5) or confirm Passport's service provider is auto-discovered.

6. Configure Auth Guard

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

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

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

Configuring Authentication Guards

Passport works with the api guard by default. You can use Passport for other guards if needed, but sticking to the default is advisable for most REST APIs.


Building a Simple REST API

Let’s create a simple "Post" resource with authentication:

1. Create a Model, Migration, and Controller

php artisan make:model Post -mcr

Add fields to database/migrations/xxxx_xx_xx_create_posts_table.php:

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->string('title');
        $table->text('body');
        $table->timestamps();
    });
}

Run migration:

php artisan migrate

2. Define API Routes

In routes/api.php:

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

Route::middleware('auth:api')->group(function() {
    Route::apiResource('posts', PostController::class);
    Route::post('logout', [AuthController::class, 'logout']);
});

3. Create an Auth Controller

Generate controller:

php artisan make:controller AuthController

Implement registration, login, and logout methods in app/Http/Controllers/AuthController.php:

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

public function register(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|string|min:8|confirmed',
    ]);

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

    $token = $user->createToken('Personal Access Token')->accessToken;

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

public function login(Request $request)
{
    $credentials = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (!Auth::attempt($credentials)) {
        throw ValidationException::withMessages([
            'email' => ['The provided credentials are incorrect.'],
        ]);
    }

    $user = Auth::user();
    $token = $user->createToken('Personal Access Token')->accessToken;

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

public function logout(Request $request)
{
    $request->user()->token()->revoke();
    return response()->json(['message' => 'Successfully logged out']);
}

4. Implement Resource Controller

Edit app/Http/Controllers/PostController.php and implement standard CRUD functions (index, store, show, update, destroy).

Example - restrict posts to authenticated users:

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required',
        'body' => 'required',
    ]);

    $post = $request->user()->posts()->create($validated);

    return response()->json($post, 201);
}

Protecting Routes with Passport

The auth:api middleware restricts routes to clients who provide valid Bearer tokens.

Example request header:

Authorization: Bearer {access_token}

Attempting to access protected endpoints without a valid token returns a 401 Unauthorized error.


Testing the API

You can use tools like Postman or curl to interact with your API:

1. Register

curl -X POST http://localhost/api/register \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane Doe", "email":"jane@doe.com", "password":"secret123", "password_confirmation":"secret123"}'

2. Login

curl -X POST http://localhost/api/login \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@doe.com", "password":"secret123"}'

Save the access_token from the response.

3. Call Protected Route

curl -X GET http://localhost/api/posts \
  -H "Authorization: Bearer {access_token}"

Conclusion

Laravel Passport makes implementing OAuth2 authentication in your REST API effortless, bringing robust security features and token management. Passport's out-of-the-box functionality saves hours of manual configuration while staying aligned with industry best practices.

Now your Laravel API is ready to securely interact with external applications and SPAs!


References:


Happy Coding!