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

Synchro's avatar

Decoding Passport refresh tokens

I'm using Laravel Passport with an API using a Password credential flow. This issues access and refresh tokens as it should. I'm having some trouble with the refresh token mechanism complaining of invalid tokens, so I'm trying to trace the flow through the system.

I see that Passport has an oauth_refresh_tokens table that stores a refresh token id (apparently an id of a token, not the token itself) and an access token id. When a client submits a request to /oauth/token with a refresh_token grant type, I'm expecting it to look up the refresh token in this table to check its validity. However, this is clearly not what is going on because a refresh token is about 700 chars, and the refresh token table fields are only 100 chars, so it will never match directly.

So I'm wondering what internal structure the refresh token has, if any, but not having any luck. It's not JWT like the access token, base64-decoding reveals nothing, and I've seen various things saying it's an opaque token, i.e. just a random string - in which case 700 chars seems really excessive.

Given a refresh token, how can I obtain the refresh token ID from it to look it up in the DB?

0 likes
2 replies
LaryAI's avatar
Level 58

The refresh token generated by Laravel Passport is indeed an opaque token, which means it is just a random string and does not contain any meaningful information. The refresh token is not directly stored in the oauth_refresh_tokens table. Instead, only the hashed version of the refresh token is stored in the oauth_refresh_tokens table.

To obtain the refresh token ID from a refresh token, you can use the find method provided by the RefreshTokenRepository class. Here's an example of how you can do it:

use Laravel\Passport\RefreshTokenRepository;

// Assuming you have the refresh token stored in a variable called $refreshToken

$refreshTokenRepository = new RefreshTokenRepository();
$refreshTokenId = $refreshTokenRepository->find($refreshToken)->id;

// Now you have the refresh token ID and can use it to look it up in the DB

Make sure to include the necessary use statement for the RefreshTokenRepository class at the top of your file.

Note that the find method will return null if the refresh token is not found in the database.

Synchro's avatar

@LaryAI This looked very hopeful, but unfortunately doesn't seem to work. If I submit a password auth request, receive a new access token and refresh token, then drop the refresh token into this code, it returns null. However, if I submit an actual request to my API's refresh token endpoint using it, it works, so it seems the given code isn't the whole story.

One thing that's quite frustrating is that I can't find the code that actually implements any of this. All the code in Passport is very abstract, and I can't find a concrete implementation of anything that creates, finds, or verifies the refresh token. There's some magic at work.

Please or to participate in this conversation.