I have a project set up with laravel Sanctum that uses an access token and a refresh token.
I store the token data in a cookie.
I am trying to create a middleware that does the following: 1- Read the cookie containing the token data. 2- Check if the access token has expired. 3- Make a call to my API to refresh it. 4- Store the new value in the cookie (overwriting the old one). 5- Continue the process and the controller will receive the new access token value.
But I have a problem with step 4 and 5, I am finding it impossible to update the new value of the access token in the cookie and get it to the controller.
I have tried everything but I still can't get it, I leave you a piece of code:
$newAuthTokens = $this->adminRepository->refreshAccessToken(
new AccessToken($accessTokenData['token']),
new RefreshToken($refreshTokenData['token'])
);
$cookie = cookie(
AdminConstants::COOKIE_NAME,
Crypt::encryptString($newAuthTokens->concatenate()),
Carbon::instance(new DateTime($newAuthTokens->refreshTokenExpiredAt->value()))->diffInMinutes(Carbon::now())
);
return $next($request)
->withCookie(
cookie()->make(
AdminConstants::COOKIE_NAME,
Crypt::encryptString($newAuthTokens->concatenate()),
Carbon::instance(new DateTime($newAuthTokens->refreshTokenExpiredAt->value()))->diffInMinutes(Carbon::now())
)
);
In other words, I do this:
That's the initial thing. Now imagine that the access token that is stored in the cookie has expired and the user clicks on a link that takes him to see, for example, his list of friends, then this happens:
What happens between step 2 and 3, the middleware does not update the access token, so when the process reaches step 3 and retrieves the access token, the one it retrieves is the old value that is expired.
I need the cookie to be updated before it reaches the controller so I don't use it: $response = $next($request);
Your application receives an old value because withCookie()
method is being executed after $next($request)
is resolved to Illuminate\Http\Response
, so after the application has already processed the request.
In general, you are adding a cookie to the response, not a request.
See Middleware docs for more context.
On the other hand, I'm not a fan of the refreshing token on the fly in the middleware. You should have made a route to refresh the token which will be called if the client gets HTTP 401 Unauthorized or after a certain amount of time (expiry time).
If you really what to go that way - you can try to set a cookie on the $request
and then return $next($request)
.
I don't know which Laravel version you are using (those things have changed over time), so I'm not sure which method you should use. It would look like this:
public function handle(Request $request, Closure $next): Response
{
// Refresh token
// ...
$request = $request->method_which_will_add_cookie();
return $next($request);
}
If for some reason cookies are not accessible, you can use ReflectionClass
(docs).