Implementing Access Tokens and Refresh Tokens in Laravel Sanctum

In secure and scalable API development, authentication plays a key role. Laravel Sanctum provides a lightweight solution for managing access tokens and refresh tokens, allowing granular control over each token’s permissions. In this article, we explore its implementation, explain how it works, and demonstrate how to protect routes with a custom middleware.

Laravel Sanctum is a lightweight authentication solution for Laravel APIs. In this article, we will delve into the implementation of access tokens and refresh tokens, explaining their purpose, the necessary middleware, and the endpoint to obtain new tokens.

05.03.2025 — Marc Bernet — 5 min read

Introduction to Token Authentication

Before the advent of token-based systems, authentication in web applications primarily relied on server-side sessions. This worked well in monolithic environments, where the backend and frontend were part of the same application, but it posed challenges in modern architectures with multiple clients (mobile applications, SPAs, microservices, etc.).

Why Use Access Tokens and Refresh Tokens?

The traditional session-based authentication approach has several limitations:
    •    Scalability: Requires server-side storage for each active session.
    •    Distribution: Does not work well in distributed architectures without sharing state between servers.
    •    Expiration Handling: Sessions often last too long or require additional mechanisms for renewal.

Access and refresh tokens solve these issues by providing:
    •    Stateless authentication: Each request sends a signed token, eliminating the need to store sessions on the backend.
    •    Enhanced security: Access tokens have a short lifespan, and refresh tokens allow obtaining new access tokens without requiring user credentials.
    •    Microservices compatibility: Facilitates authentication in distributed systems, enabling multiple services to verify identity without accessing a central database.

Token Protection Middleware

The TokenAccessGuard middleware is responsible for verifying whether a token has the appropriate permissions to perform an action. Let’s take a look at its implementation:
 


namespace App\Http\Middleware;
use App\Enums\TokenAbilityEnum;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class TokenAccessGuard
{
   public function handle(Request $request, Closure $next): Response
   {
       $user = Auth::user();
       if (empty($user)) {
           return $next($request);
       }
       $token = $user->currentAccessToken();
       if ($token) {
           if ($request->routeIs('refresh-token') && $token->cant(TokenAbilityEnum::ISSUE_ACCESS_TOKEN->value)) {
               return response()->json([
                   'message' => 'Unauthorized',
                   'error' => 'Token can not issue access token',
               ], 401);
           } elseif (!$request->routeIs('refresh-token')) {
               if ($token->cant(TokenAbilityEnum::ACCESS_API->value)) {
                   return response()->json([
                       'message' => 'Unauthorized',
                       'error' => 'Token can not access api',
                   ], 401);
               }
           }
       }
       return $next($request);
   }
}

Middleware explanation

    •    Retrieves the authenticated user.
    •    Verifies if the token has the necessary permissions:
    •    If the route is refresh-token, the token must have the ISSUE_ACCESS_TOKEN ability.
    •    For all other routes, the token must have the ACCESS_API ability.
    •    If the token does not meet the required permissions, it returns a 401 Unauthorized error.

Refresh Token endpoint

This endpoint allows users to obtain a new access token using a valid refresh token: 

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Enums\TokenAbilityEnum;
use Illuminate\Support\Facades\Route;
Route::post('/refresh-token', function (Request $request) {
   $user = Auth::user();
   if (!$user) {
       return response()->json(['message' => 'Unauthorized'], 401);
   }
   $token = $user->currentAccessToken();
   if ($token->cant(TokenAbilityEnum::ISSUE_ACCESS_TOKEN->value)) {
       return response()->json([
           'message' => 'Unauthorized',
           'error' => 'Token can not issue access token',
       ], 401);
   }
   $newAccessToken = $user->createToken('access_token', [TokenAbilityEnum::ACCESS_API->value]);
   return response()->json([
       'access_token' => $newAccessToken->plainTextToken,
   ]);
});

Endpoint Explanation
    •    Retrieves the authenticated user.
    •    Verifies if the current token has the ability to issue new access tokens.
    •    If valid, generates and returns a new access token.

Conclusion

Implementing access tokens and refresh tokens in Laravel Sanctum is an effective strategy to enhance API security. The TokenAccessGuard middleware protects routes by ensuring that each token has the appropriate permissions, while the refresh-token endpoint allows obtaining new access tokens without requiring the user to reauthenticate.

This implementation ensures robust and flexible authentication for any API developed with Laravel.

💡 How much does it cost to develop an app for your business? Discover the prices