Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

GimmeMylanta's avatar

How to refresh Sanctum token

I am building an API ONLY install of Laravel. I decided to use Sanctum for issuing the tokens. In the config/sanctum.php I have set expiration for 60mins.

Once the token expires I get the standard 401 response;

{
    "message": "Unauthenticated."
}

I have read online that a refresh endpoint should look like so;

Route::get('refresh', [Auth\AuthenticationController::class, 'refresh'])->middleware('auth:sanctum');

and the method as;

public function refresh(Request $request): JsonResponse
{
    $request->user()->tokens()->delete();

    return response()->json([
        'access_token' => $request->user()->createToken('api')->plainTextToken,
    ]);
}

The problem is, that if i try and hit that endpoint with an expired token, it just gives the 401 response again. If i remove the sanctum middleware from that route, it throws Call to a member function tokens() on null

Does Sanctum have the ability to issue a refresh token? What is the correct way to refresh a token?

0 likes
5 replies
Hellocode's avatar

You can create a new table or field to save the time when the user acquired the token, and then the client will poll and re-obtain the new token for the client just a few minutes before the expiry token.

1 like
RapRaf's avatar

The issue in your code is that you are revoking the token before issuing the new one. Revoke it after.

osama_98's avatar

Why not trying to customize the refresh token function ? By sending the expired token in header like what you are doing in authorized apis.

    if (empty($token = $request->header('Authorization'))) {
        return response()->json(['message' => 'Token is invalid'], 422);
    }

    $token = explode('Bearer ', $token);
	if(empty($token[1]) || empty($token = PersonalAccessToken::findToken($token[1]))) {
		return response()->json(['message' => 'Token is invalid'], 422);
	}

    if (!$token->tokenable instanceof User) {
        return response()->json(['message' => 'Token is invalid'], 422);
    }

    return response()->json([
        'status' => 'success',
        'data' => ['access_token' => $token->tokenable->createToken('access-token')->plainTextToken]
    ]);
2 likes
Kate_Koltsova's avatar

I could be wrong, but I think the error "Call to a member function tokens() on null" occurs here "$request->user()->tokens()->delete();", your tokens() function is called only in one place, $request->user() will return null. With an unexpired token this should not work either, the refresh method only includes the token itself in text form, which you can then find in your table, as osama_98 wrote above, and then you can get the tokenable user

Please or to participate in this conversation.