Manage refresh Token and acces Token with Laravel Sanctum

BOKO Marc Uriel
5 min readDec 12, 2023

--

During one of my recent projects, I had to develop a refresh token system after authentication using Laravel. Several packages were suggested to achieve this, but I didn’t want to use a package or utilize JWT for it. Instead, I aimed to employ Laravel Sanctum without installing an external package.In this article i will share with you how i achieve this goal without use another else package .

After a few days of research and thinking, I finally came up with an idea. The idea is simple yet effective: when a user logs in, I’ll generate two differents tokens with different expiration times and abilities. One will be used for the refresh token, and the other for accessing the API. We’ll utilize Laravel Sanctum’s check ability’ middleware to verify the ability on the route that renews the token using the refresh token after acces token expiration. Then, we’ll check for other routes that require a token to access the API.

Enough talking, let’s dive into coding.

First of all let’s create a laravel new project.

I hope you are confortable with Laravel and have all dependencies installed such as composer , postgresql or mysql , php .

laravel new laravel-sanctum-refresh-token
touch .env
cp .env.example .env
php artisan key:generate
composer install
php artisan migrate

Well, now we have a Laravel project installed and properly configured on your machine is a good starting point.

For the next step, we’ll create our two abilities as I mentioned at the beginning of the article. We’ll have two abilities: one that will allow us to protect the routes of our API, and a second one that will enable us to generate an access token when it expires.

I chose to use enums, but you’re free to use constants, variables, or any method you prefer.

<?php

namespace App\Enums;

enum TokenAbility: string
{
case ISSUE_ACCESS_TOKEN = 'issue-access-token';
case ACCESS_API = 'access-api';
}

Good, There is a difference in the time-to-live between access tokens and refresh tokens but Sanctum has only one configuration for expiration in config/sanctum.php. Let's start by adding another configuration for both refresh and access tokens expiration named respectivelyrt_expiration ac_expiration

<?php

return [
'expiration' => null // default laravel expiration set as null
'ac_expiration' => 60, // One hour
'rt_expiration' => 7 * 24 * 60, // 7 Days
];

You’ll notice that I’ve set an hour for my access token and a week for the refresh token. Depending on your project and the level of security you desire, you can set the time as per your requirements. However, remember to allocate more time to the refresh token than to the access token and ensure the time is defined in minutes.

Now that everything is in place to generate tokens for our users, let’s start by adding our controller.

php artisan make:controller AuthController

Add register function in AuthController

 public function register()
{
$data = ['name' => "Marc BOKO", "password" => "123456789", "email" => "marcboko.uriel@gmail.com"];
$user = User::create($data);
$accessToken = $user->createToken('access_token', [TokenAbility::ACCESS_API->value], Carbon::now()->addMinutes(config('sanctum.ac_expiration')));
$refreshToken = $user->createToken('refresh_token', [TokenAbility::ISSUE_ACCESS_TOKEN->value], Carbon::now()->addMinutes(config('sanctum.rt_expiration')));

return [
'token' => $accessToken->plainTextToken,
'refresh_token' => $refreshToken->plainTextToken,
];
}

Then add route in routes/api.php

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

In the register function, I attempted to quickly register a user and then generated two tokens: the access token and the refresh token. The createToken method takes three parameters: the first one is the name of the token we’re generating, the second one is the ability assigned to this token here, we used the abilities we created at the beginning of our article, and the last parameter is the token’s validity period. Here, we used the time durations we defined in our config/sanctum.php file.

Token generate after register
Token generate after register
Token abilities and expired_at stored in personal_acces_token table

We’ll now use the CheckAbilities middleware provided by Laravel Sanctum. To do this, we’ll add the two middleware to our app/kernel.php. As mentioned at the beginning of the article, these middleware enable us to verify the ability of a token generated by Laravel Sanctum. They’ll help us check the ability of the token used to regenerate a new token and the one used in the project to access protected routes.

'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class,
'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class,

Let’s now create our function and the route that will allow us to generate an access token using a refresh token when it expires.

Add refreshToken function in AuthController.php

public function refreshToken(Request $request)
{
$accessToken = $request->user()->createToken('access_token', [TokenAbility::ACCESS_API->value], Carbon::now()->addMinutes(config('sanctum.ac_expiration')));
return response(['message' => "Token généré", 'token' => $accessToken->plainTextToken]);
}

Nothing new here, we simply used the createToken method to create a new token with the access token ability and its expiration time. Now, let’s create the route.

Route::middleware('auth:sanctum', 'ability:' . TokenAbility::ISSUE_ACCESS_TOKEN->value)->group(function () {
Route::get('/auth/refresh-token', [AuthController::class, 'refreshToken']);
});

You’ll notice that we used the ability middleware provided by Laravel Sanctum to ensure that the token we’re using to generate an access token is indeed a refresh token and that it has the ability to perform this action. Then, we have the auth:sanctum middleware, which ensures that the token is valid and not expired.

Token geneate succefuly with refresh token as Bearer Token
Token not generated with acces token use as Bearer Token

Finally, to protect our routes with our access token, we can do it like this

Route::middleware('auth:sanctum', 'ability:' . TokenAbility::ACCESS_API->value)->get('/me', function (Request $request) {
return $request->user();
});

In summary, refresh tokens can make your application more secure but because they are powerful authentication artifacts, they should be kept secure. You can learn more about securing refresh tokens from this article.

We’ve reached the end of this article; I hope you enjoyed it as much as I did. Feel free to leave your comments and like as much as possible. I’ll leave a GitHub link to the complete project.

https://github.com/boko-marc/laravel-sanctum-refresh-token

--

--

BOKO Marc Uriel

Backend Developer | I share my daily challenges and newfound knowledge about Backend Software.. Follow me https://www.linkedin.com/in/marc-uriel-zinsou-boko/me