Get started with 33% off your first certification using code: 33OFFNEW

Gates, Policies and API authentication in Laravel

5 min read
Published on 27th June 2024

Laravel, a popular PHP framework, offers a robust authorization system that makes it easy to handle user permissions and access control. This article provides an in-depth look at Laravel's gates and policies, along with how to implement API authentication. By the end of this guide, you'll have a solid understanding of these features and how to use them to secure your Laravel applications.

Understanding Authorization in Laravel

Laravel provides two primary ways to authorize actions: gates and policies. Both methods help determine if a user is authorized to perform a given action. Gates are typically used for simple authorization checks, while policies are used for more complex scenarios.

Gates in Laravel

Gates are simple, Closure-based authorization checks that you define within your application. Gates provide a great way to control access to specific actions in a concise and straightforward manner.

Defining Gates

You can define gates in the App\Providers\AuthServiceProvider class. Use the Gate facade to define a gate.

// App\Providers\AuthServiceProvider.php

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $this->registerPolicies();

        Gate::define('update-post', function ($user, $post) {
            return $user->id === $post->user_id;
        });
    }
}

In this example, the gate named update-post checks if the authenticated user is the owner of the post.

Using Gates

You can use gates in various parts of your application, such as controllers, routes, or views. Use the Gate::allows method to check if a user is authorized to perform an action.

use Illuminate\Support\Facades\Gate;

if (Gate::allows('update-post', $post)) {
    // The user can update the post
} else {
    // The user cannot update the post
}

You can also use the can method provided by the Authorizable trait in Eloquent models.

if ($user->can('update-post', $post)) {
    // The user can update the post
}

Policies in Laravel

Policies are classes that organize authorization logic around a particular model or resource. They provide a more structured and organized way to handle complex authorization scenarios.

Generating Policies

You can generate a policy using the Artisan command:

php artisan make:policy PostPolicy

This command creates a new policy class in the app/Policies directory.

Defining Policies

Define your policy methods to authorize actions on a given model. Each policy method corresponds to a specific action.

// App\Policies\PostPolicy.php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

Registering Policies

You need to register the policy in the AuthServiceProvider. This links the policy to the corresponding model.

// App\Providers\AuthServiceProvider.php

use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    public function boot()
    {
        $this->registerPolicies();
    }
}

Using Policies

You can use policies in your controllers or routes to authorize actions. Use the authorize method to check if the user is authorized to perform a given action.

public function update(Request $request, Post $post)
{
    $this->authorize('update', $post);

    // The user can update the post
}

You can also use the can method in your views or Blade templates.

@can('update', $post)
    <button>Update Post</button>
@endcan

API Authentication in Laravel

Laravel provides several methods to authenticate APIs, including Laravel Passport, Laravel Sanctum, and basic API tokens. Each method has its use cases and benefits.

Using Laravel Passport

Laravel Passport provides a full OAuth2 server implementation for your Laravel application. It is ideal for building robust, production-ready APIs.

  1. Installing Passport

    Install Passport using Composer:

    composer require laravel/passport
    
  2. Migrating the Database

    Run the migrations to create the necessary tables:

    php artisan migrate
    
  3. Installing Passport

    Install Passport by running the passport:install Artisan command:

    php artisan passport:install
    
  4. Configuring AuthServiceProvider

    Register the Passport service provider in your AuthServiceProvider:

    use Laravel\Passport\Passport;
    
    public function boot()
    {
        $this->registerPolicies();
    
        Passport::routes();
    }
    
  5. Configuring the API Guard

    Set the api guard to use the passport driver in your config/auth.php file:

    'guards' => [
        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],
    
  6. Protecting Routes

    Use the auth:api middleware to protect your API routes:

    Route::middleware('auth:api')->get('/user', function (Request $request) {
        return $request->user();
    });
    

Using Laravel Sanctum

Laravel Sanctum provides a simple token-based authentication system for SPAs (single page applications), mobile applications, and basic token-based APIs.

  1. Installing Sanctum

    Install Sanctum using Composer:

    composer require laravel/sanctum
    
  2. Publishing the Sanctum Configuration

    Publish the Sanctum configuration file:

    php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
    
  3. Migrating the Database

    Run the migrations to create the necessary tables:

    php artisan migrate
    
  4. Configuring Sanctum Middleware

    Add Sanctum's middleware to your api middleware group within your app/Http/Kernel.php file:

    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
    
  5. Issuing API Tokens

    You can issue tokens to users by calling the createToken method on the user model:

    $user = User::find(1);
    $token = $user->createToken('MyAppToken')->plainTextToken;
    
    return response()->json(['token' => $token]);
    
  6. Protecting Routes

    Use the auth:sanctum middleware to protect your API routes:

    Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
        return $request->user();
    });
    

Combining Gates, Policies, and API Authentication

By combining gates, policies, and API authentication, you can build a secure and flexible authorization system in your Laravel application. Here’s an example of how you might do this:

  1. Defining a Gate

    // App\Providers\AuthServiceProvider.php
    
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
    use Illuminate\Support\Facades\Gate;
    
    class AuthServiceProvider extends ServiceProvider
    {
        public function boot()
        {
            $this->registerPolicies();
    
            Gate::define('view-profile', function ($user, $profile) {
                return $user->id === $profile->user_id;
            });
        }
    }
    
  2. Creating a Policy

    // App\Policies\ProfilePolicy.php
    
    namespace App\Policies;
    
    use App\Models\Profile;
    use App\Models\User;
    
    class ProfilePolicy
    {
        public function view(User $user, Profile $profile)
        {
            return $user->id === $profile->user_id;
        }
    
        public function update(User $user, Profile $profile)
        {
            return $user->id === $profile->user_id;
        }
    }
    
  3. Registering the Policy

    // App\Providers\AuthServiceProvider.php
    
    use App\Models\Profile;
    use App\Policies\ProfilePolicy;
    
    protected $policies = [
        Profile::class => ProfilePolicy::class,
    ];
    
    public function boot()
    {
        $this->registerPolicies();
    }
    
  4. Protecting API Routes

    // routes/api.php
    
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    
    Route::middleware('auth:api')->group(function () {
        Route::get('/profile/{profile}', function (Request $request, Profile $profile) {
            $this->authorize('view', $profile);
    
            return $profile;
        });
    
        Route::put('/profile/{profile}', function (Request $request, Profile $profile) {
            $this->authorize('update', $profile);
    
            $profile->update($request->all());
    
            return $profile;
        });
    });
    

Conclusion

Understanding and implementing gates, policies, and API authentication in Laravel is crucial for building secure and scalable applications. Gates provide a simple way to handle basic authorization, while policies offer a structured approach for complex scenarios. By combining these with robust API authentication mechanisms like Laravel Passport and Laravel Sanctum, you can ensure that your application is both secure and flexible.

For more details, refer to the official Laravel documentation:

By mastering these tools, you'll be well-equipped to manage user permissions and secure your Laravel applications effectively.