Harnessing Laravel’s AuthGates Middleware for API Testing with Postman

Amin
mabttech
Published in
4 min readFeb 9, 2024

Harnessing Laravel's AuthGates Middleware for API Testing with Postman

Introduction

Laravel, a robust PHP framework, offers an elegant way to handle authorization logic using Gates. For developers working with APIs, testing these authorization features is crucial, and Postman serves as an excellent tool for this purpose. In this post, we'll explore how to effectively use Laravel's AuthGates middleware for API testing with Postman.

Understanding AuthGates Middleware

The AuthGates middleware in Laravel dynamically defines authorization gates based on roles and permissions. It's a crucial piece in managing access control within your application. Here's a glimpse of what the AuthGates middleware looks like:

namespace App\Http\Middleware;

use App\Models\Role;
use Closure;
use Illuminate\Support\Facades\Gate;

class AuthGates
{
public function handle($request, Closure $next)
{
$user = auth()->user();
if (! $user) {
return $next($request);
}

$roles = Role::with('permissions')->get();
$permissionsArray = [];

foreach ($roles as $role) {
foreach ($role->permissions as $permissions) {
$permissionsArray[$permissions->title][] = $role->id;
}
}

foreach ($permissionsArray as $title => $roles) {
Gate::define($title, function ($user) use ($roles) {
return count(array_intersect($user->roles->pluck('id')->toArray(), $roles)) > 0;
});
}

return $next($request);
}
}

Configuring Kernel and API Routes

To ensure AuthGates works with API routes, adjustments in the Kernel.php and api.php files are necessary. Here's how to apply AuthGates middleware to the api middleware group in Kernel.php:

protected $middlewareGroups = [


'web' => [
// ... existing middleware ...
\App\Http\Middleware\AuthGates::class, // Keep it here if you also want it for web routes
],


'api' => [
// ... existing middleware ...
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\AuthGates::class, // Add this line to apply AuthGates to API routes
],

];

In api.php, ensure that your routes are correctly set up for API endpoints and authentication: .


<?php

Route::get('/test', function () {
return 'API is working';
});


Route::post('register', 'Api\V1\AuthController@register');
Route::post('login', 'Api\V1\AuthController@login');
Route::post('login', 'Api\V1\AuthController@login')->name('login'); // this is used to be redirected to a page upon error / issue ...Etc


Route::group(['prefix' => 'v1', 'as' => 'api.', 'namespace' => 'Api\V1\Admin', 'middleware' => ['auth:sanctum']], function () {

// Permissions
Route::apiResource('permissions', 'PermissionsApiController');

// Roles
Route::apiResource('roles', 'RolesApiController');

// Users
Route::apiResource('users', 'UsersApiController');


// ... other routes ...

});

.

Testing with Postman

  1. Authenticate: Use the login endpoint to obtain an authentication token.
  2. Set Authorization Header: Include the token in the Authorization header in Postman:
Authorization : Bearer YOUR_TOKEN_HERE

3. Send Requests: Make requests to your API and observe the responses. The AuthGates middleware should apply your gate definitions.

How Gates work in controllers “UsersController.php” example ?

Laravel Gates are used to define authorization logic. They determine if a particular user is authorized to perform an action. In your application, these gates are likely defined in the AuthServiceProvider or a similar service provider.

Usage in UsersController

  1. Index Method (public function index()):
  • This method lists all users.
  • Gate::denies('user_access'): Checks if the current user does not have the 'user_access' permission.
  • If the user lacks this permission, the request is aborted with a 403 Forbidden response.
  • If the user has the permission, the method proceeds to fetch and display users.

2. Create Method (public function create()):

  • This method displays a view to create a new user.
  • Gate::denies('user_create'): Checks if the current user is not authorized to create a user.
  • If unauthorized, it aborts with a 403 response; otherwise, it proceeds to the view.

3. Store Method (public function store(StoreUserRequest $request)):

  • Handles the creation of a new user.
  • There’s no explicit gate check here, but it’s assumed that the route to this method is protected.

4. Edit Method (public function edit(User $user)):

  • This method displays a view for editing a user.
  • Gate::denies('user_edit'): Checks if the current user is unauthorized to edit users.
  • If unauthorized, it aborts; otherwise, it proceeds with the edit view.

5. Update Method (public function update(UpdateUserRequest $request, User $user)):

  • Handles updating a user’s details.
  • Like the store method, it doesn’t explicitly check a gate but relies on route-level protection.

6. Show Method (public function show(User $user)):

  • Displays a single user’s details.
  • Gate::denies('user_show'): Checks if the current user cannot view user details.
  • If unauthorized, it aborts; otherwise, it proceeds to show the user details.

7. Destroy Method (public function destroy(User $user)):

  • Handles the deletion of a user.
  • Gate::denies('user_delete'): Checks if the current user is unauthorized to delete users.
  • If unauthorized, it aborts; otherwise, it deletes the user.

8. MassDestroy Method (public function massDestroy(MassDestroyUserRequest $request)):

  • Handles the deletion of multiple users.
  • No explicit gate check, but assumed to be protected at the route level.

Commented Example from index Method : .

public function index()
{
// Check if the current user is not allowed to access user data
abort_if(Gate::denies('user_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');

// If authorized, fetch all users with their associated roles
$users = User::with(['roles'])->get();

// Return the view with the users data
return view('admin.users.index', compact('users'));
}

In each case, the Gate::denies method is used to check if the current user is unauthorized to perform a specific action. If the user is unauthorized, the request is aborted with a 403 Forbidden response. This pattern effectively enforces authorization checks before proceeding with any potentially sensitive operations related to user management.

--

--