16

When I run $user->currentAccessToken()->delete(); the token expires, Auth::check() becomes false, what it is expected.

However, when I go to the personal_access_tokens table, the token is still there. There is no soft delete field. How does Sanctum now that the token is expired?

Inigo EC
  • 2,178
  • 3
  • 22
  • 31
  • `sanctum.php` inside `'expiration' => null,` you can set – Kamlesh Paul Sep 29 '20 at 09:50
  • @KamleshPaul, yes, but that's based on the creation time, not in the last time used, which is not ideal. What's the point on having a 1 day expiration token if the user is continously using the app? Not a good user experience if you are using it and suddently gets log out – Inigo EC Sep 29 '20 at 10:19

4 Answers4

27

You can set in config/sanctum.php array node expiration

/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/

'expiration' => 60 * 24 * 7,
9

As of writing this answer, the token now deletes from the database so that one is settled.

How Sanctum knows if a token is expired is pretty simple:

  • The token has a created date, call it C
  • The config data in config/sanctum.php has an expiration time, call it E
  • The current time you want to use the token is right now, call it N

To check for expiry, it subtracts N from C. If N - C is less than E, the token hasn't expired yet. If it is greater, the token is expired.

Example:

  • You created a token at 5:00 AM
  • The expiration time is set for 5 hours
  • You want to access data through the token at 8:00 AM

When you subtract 8 from 5, you get 3. That's just 3 hrs since you created the token. Not up to the 5 hrs you set.

If you were accessing data at say, 11:00 AM, then the time frame becomes 6 hrs, which is more than 5 hrs, meaning the token has expired.

Joshua Etim
  • 206
  • 2
  • 5
  • 1
    i proven that this method is correct. But would it be possible to use the last_used_at to be the 'C'. In that case if the token have been stale for 'E' minutes then it would be considered as expired. – grit May 04 '22 at 00:54
  • 1
    it is possible, but you would have to implement that manually. you can start by looking at the tokens table (personal_access_tokens) and use your logic and DB queries to achieve your goals – Joshua Etim May 11 '22 at 11:34
4

I looked in the source code of sanctumm and it seems like it's a guard that handles it.

      if (! $accessToken ||
                ($this->expiration &&
                 $accessToken->created_at->lte(now()->subMinutes($this->expiration))) ||
                ! $this->hasValidProvider($accessToken->tokenable)) {
                return;
            }

This means that the validating token proccess looks like this:

  • Check if token is present in database
  • Check if token creation_date hasnt surpassed the expiration time
  • Check if the tokenable model matches the provider's model type
  • Check if the tokenable model supports API tokens

And upon fail, it's simply rejecting the request. Not deleting the token.

Deleting the token is however the manual way to revoke a token.

You may "revoke" tokens by deleting them from your database using the tokens relationship that is provided by the HasApiTokens trait:

PatricNox
  • 3,306
  • 1
  • 17
  • 25
  • 1
    Thanks! but that's the thing, when I do `$user->currentAccessToken()->delete();` it does revoke the token, but it doesn't get deleted from the database. I guess my question is, how does Sanctum know that the token has expired? – Inigo EC Sep 29 '20 at 10:18
  • 1
    @InigoEC I thought that was the question that I answered, Sanctum doesn't modify the token in anyway, but rejects the request when its expired. The reason for your delete method to not work is most likely some misconfiguration. Have you added the trait `HasApiTokens ` in user model? – PatricNox Sep 29 '20 at 11:04
  • Hi @PatricNox, so how does Sanctum check that it's expired? Assuming that the expiration is null in the sanctum config file and I manually expire it using `$user->currentAccessToken()->delete();`; There is nothing like "expired_at" in the DB – Inigo EC Sep 29 '20 at 11:32
  • @InigoEC If you remove the token, it's handled as a revoked token. Otherwise, the record will be there even though it has expired, by default. Sanctum compares expiration time against the created_at field, not expired_at – PatricNox Sep 29 '20 at 19:11
  • 1
    Where is the expiration time defined? – trainoasis Dec 11 '20 at 14:16
  • @trainoasis The expiration time is defined in your config file for Sanctum. `./config/santum.php` – PatricNox May 24 '22 at 07:13
  • @PatricNox Hi, I have set the `expiration` to `1800` from `/config/sanctum.php/` but its still empty in the database, I think it's for a migration file that accepts `nullable` too, but if I remove `nullable` from there, the process of running the command for migrating and seeding of tables throws an error that filed can not be null, so what should I do? – Mohammad Oct 09 '22 at 15:58
  • @Mohammad sounds like a $fillable thing – PatricNox Oct 14 '22 at 13:56
1

The code below would only return a token as valid if its last_used_at is greater than or equal to 72 hours. Just put this inside the AppServiceProvider & change the 72 to reflect the number of hours of inactivity you want it to react to.

use Laravel\Sanctum\Sanctum;
Sanctum::$accessTokenAuthenticationCallback = function ($accessToken, $isValid){
        return !$accessToken->last_used_at || $accessToken->last_used_at->gte(now()->subHours(72));
    };
Fred Ebho
  • 26
  • 3