PHPackages                             laragear/token-action - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. laragear/token-action

ActiveLibrary[Security](/categories/security)

laragear/token-action
=====================

Use tokens to accept or reject actions a limited number of times.

v3.0.0(3mo ago)41.1k↓86.7%1MITPHPPHP ^8.3CI passing

Since Jul 25Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/Laragear/TokenAction)[ Packagist](https://packagist.org/packages/laragear/token-action)[ Docs](https://github.com/laragear/token-action)[ Fund](https://github.com/sponsors/DarkGhostHunter)[ Fund](https://paypal.me/darkghosthunter)[ RSS](/packages/laragear-token-action/feed)WikiDiscussions 3.x Synced today

READMEChangelog (7)Dependencies (8)Versions (15)Used By (1)

Token Action
============

[](#token-action)

[![Latest Version on Packagist](https://camo.githubusercontent.com/56df1343361349b1a22e5445a4d64e07b1eb15ceb628659b31117e93df707569/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c617261676561722f746f6b656e2d616374696f6e2e737667)](https://packagist.org/packages/laragear/token-action)[![Latest stable test run](https://github.com/Laragear/TokenAction/workflows/Tests/badge.svg)](https://github.com/Laragear/TokenAction/actions)[![Codecov Coverage](https://camo.githubusercontent.com/23d0f736ab87e33e2ee489bdb04acb674cbb4a18382095e9ff420ae6215cb9c1/68747470733a2f2f636f6465636f762e696f2f67682f4c617261676561722f546f6b656e416374696f6e2f67726170682f62616467652e7376673f746f6b656e3d596a4a70644b72554372)](https://codecov.io/gh/Laragear/TokenAction)[![Maintainability](https://camo.githubusercontent.com/582dc7ff82b0b501b4136cd5523348d27f7d267ae70ca1aee41a62125c006cc4/68747470733a2f2f716c74792e73682f6261646765732f31383263353734322d653038622d343034392d393632342d3262633639383038363964392f6d61696e7461696e6162696c6974792e737667)](https://qlty.sh/gh/Laragear/projects/TokenAction)[![Sonarcloud Status](https://camo.githubusercontent.com/cc3e6e56bdaab4d1078881d033b4ac626084ccf1f2c29101f6bc53f5f7ec73bb/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d4c617261676561725f546f6b656e416374696f6e266d65747269633d616c6572745f737461747573)](https://sonarcloud.io/dashboard?id=Laragear_TokenAction)[![Laravel Octane Compatibility](https://camo.githubusercontent.com/70359a356da237cd29561bc5d0bb80baae775b5ff62f288ed324755382858342/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2532304f6374616e652d436f6d70617469626c652d737563636573733f7374796c653d666c6174266c6f676f3d6c61726176656c)](https://laravel.com/docs/11.x/octane#introduction)

Use tokens to accept or reject actions a limited number of times.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::until('tomorrow');

return "Confirm the invite using this code: $token";
```

Use them for one-time actions like confirming invites or voting, which after consumed are no longer valid.

Keep this package free
----------------------

[](#keep-this-package-free)

[![](.github/assets/support.png)](https://github.com/sponsors/DarkGhostHunter)

Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can **spread the word on social media**.

Requirements
------------

[](#requirements)

- PHP 8.3 or later
- Laravel 12 or later.

Installation
------------

[](#installation)

Fire up Composer and require this package in your project.

```
compose require laragear/token-action
```

That's it.

How it works
------------

[](#how-it-works)

Tokens are persisted in your application Cache using a randomly generated key and a default prefix.

By default, Token Action will use the default Laravel cache. You may set a custom cache using the `TOKEN_ACTION_STORE` environment variable, for example, to use a persistent cache (like `database`, `file` or `redis`) instead of ephemeral ones like `memcache` or `array`.

```
TOKEN_ACTION_STORE=file
```

Tokens have a number of "tries" available. When a token reaches 0 tries, is deleted from the cache.

Creating Tokens
---------------

[](#creating-tokens)

Tokens can be created using the `until()` method of the `Token` facade, along with the moment in time it should expire. You may use an amount of minutes, a `\DateTimeInterface` like a Carbon instance, or a string to parse by [`strtotime()`](https://www.php.net/manual/function.strtotime.php).

```
use Laragear\TokenAction\Facades\Token;

// Create a token for 10 minutes
$token = Token::until(10);

// Create a token for tomorrow
$token = Token::until('tomorrow');

// Create a token for a specific moment of time
$token = Token::until(now()->addHour());
```

You will receive a `Laragear\TokenAction\Token` instance, already persisted in the database, with a random ID accessible as the `id` property.

You may use the ID string to, for example, send it in email or to be part of a URL parameter. The Token instance is *castable* to the ID string, so you can safely output it as text if you need to.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::until('tomorrow');

return route('party.invite', [
    'party' => 420,
    'user_id' => 10,
    'token' => (string) $token,
]);

// https://myapp.com/party/420/invite?user_id=10&token=e9f83d...
```

### Multiple-use tokens

[](#multiple-use-tokens)

Tokens are single use by default, but you can create tokens that can be consumed a limited number of times using the `tries()` method along with the number of tries.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::tries(2)->until('tomorrow');
```

Tokens can later be [*consumed more than once*](#consuming-more-than-once).

### Payloads

[](#payloads)

Tokens can be saved with a payload through the `with()` method, like an array or a string.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::with(['cool' => true])->until('tomorrow');
```

You may also add an Eloquent Model or Eloquent Collection as a payload. These are serialized using their primary key and without relations to avoid hitting cache size constraints.

```
use Laragear\TokenAction\Facades\Token;
use App\Models\Tour;
use App\Models\Party;

// Use a single model
$token = Token::with(Party::find(420))->until('tomorrow');

// Use a collection
$token = Token::with(Tour::limit(10)->get())->until('tomorrow');
```

After you [retrieve the token](#retrieving-tokens), the payload will be included as the `payload` property.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::find('e9f83d...');

if ($token) {
    $party = $token->payload->party->name;

    return "You confirmed the invitation to $party";
}

return 'You need to be invited the first place.';
```

Important

Token payloads are read-only. If you need to change the payload, consider cloning the data.

Retrieving tokens
-----------------

[](#retrieving-tokens)

The most straightforward way to use Tokens is to call the `consume()` method of the `Token` facade. If the token ID exist, has not expired, and has at least 1 try left, it will be returned as a `Token` instance, otherwise it will return `null`.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::consume('e9f83d...');

if ($token) {
    return 'You are confirmed your invitation to the party!'.
}
```

If you want to *fail* if the token is not found, use the `consumeOrFail()`, which returns an HTTP 404 (Not Found) exception.

```
use Laragear\TokenAction\Facades\Token;

Token::consumeOrFail('e9f83d...');

return 'You are confirmed your invitation to the party #420';
```

### Finding a token

[](#finding-a-token)

If you need to retrieve a token without consuming it, use the `find()` method of the `Token` facade. If the token exists, and has tries, you will receive a `Laragear\TokenAction\Token` instance, otherwise `null` will be returned.

After the token is retrieved, **you should use the `consume()` method to actually consume the token**. If the token has many tries, consuming it once will subtract one from the number of tries.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::find('e9f83d...');

if ($token?->consume()) {
    return 'Assistance confirmed!';
}

return 'You are not invited';
```

If you want to find a token or fail by returning an HTTP 404 (Not found) exception, use the `findOrFail()` method with the token id.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::findOrFail('e9f83d...');

$token->consume();

return 'Assistance confirmed!';
```

### Route binding

[](#route-binding)

If you want to retrieve a token as part of your route action, use the `token` as route key to bind it. In your route action you should type hint the Token as `$token`.

As with models, if the token doesn't exist or has expired, an HTTP 404 (Not Found) exception will be thrown.

```
use App\Models\Party;
use Illuminate\Support\Facades\Route;
use Laragear\TokenAction\Token;

Route::get('party/{party}/invitation/{token}', function (Party $party, Token $token) {
    return view('party.confirm')->with([
        'party' => $party,
        'token' => $token,
    ]);
})
```

If the `token` route key is already used by your application, you can [change in the configuration](#route-binding-key).

Deleting tokens
---------------

[](#deleting-tokens)

The only way to delete a token is knowing its ID. If you have a `Token` instance, you can use the `delete()` method.

```
use Laragear\TokenAction\Facades\Token;

$token = Token::find('e9f83d...');

if ($token) {
    $token->delete();
}
```

You may also use the `destroy()` method of the `Token` facade with the ID of the token.

```
use Laragear\TokenAction\Facades\Token;

Token::destroy('e9f83d...');
```

Cache Store
-----------

[](#cache-store)

You can change the cache store to use for managing tokens at runtime with the `store()` method.

```
use Laragear\TokenAction\Facades\Token;

$partyToken = Token::store('redis')->find('e9f83d...');

$dateToken = Token::store('memcached')->find('e9f83d...');
```

Alternatively, you can change the [default cache store](#cache) to use.

Middleware
----------

[](#middleware)

This package comes with two middlewares, `token.validate` and `token.consume`.

The `token.validate` middleware checks if a token exists, but doesn't consume it. This is great, for example, to show a view with a form as long the token has enough tries and has not expired.

```
use Illuminate\Support\Facades\Route;
use App\Models\Party;

// Show the form to confirm the invitation.
Route::get('{party}/confirm', function (Party $party) {
    return view('party.confirm')->with('party', $party);
})->middleware('token.validate');
```

On the other hand, the `token.consume` middleware automatically consumes a token from the parameters URL once a successful response is returned. In other words, if the response is successful (HTTP 2XX) or a redirection (HTTP 3XX), the token is consumed.

This should be used, for example, when receiving a form submission from the frontend.

```
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use App\Models\Party;

// Show the form to confirm the invitation.
Route::get('{party}/confirm', function (Party $party) {
    // ...
})->middleware('token.validate');

// Handle the form submission.
Route::post('{party}/confirm', function (Request $request, Party $party) {
	$party->confirmInviteForUser($request->user());

	return back();
})->middleware('token.consume');
```

Important

These middleware work over the **query URL exclusively**. If you have set the token outside the query URL, you should check that manually in your route action.

### Token parameter Key

[](#token-parameter-key)

Both `token.validate` and `token.consume` middleware try to find the token in the `token` URL parameter. If the token resides in another key, you can point it out as an argument.

```
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use App\Models\Party;

Route::get('{party}/confirm', function (Party $party) {
	// ...
})->middleware('token.validate:token-action');

Route::post('{party}/confirm', function (Request $request, Party $party) {
	// ...
})->middleware('token.consume:token-action');
```

### Consuming more than once

[](#consuming-more-than-once)

When using the `token.consume` middleware, tokens are consumed exactly 1 time. You may change it by setting a number as last middleware argument.

```
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use App\Models\Party;

Route::post('{party}/confirm', function (Request $request, Party $party) {
	// ...
})->middleware('token.consume:2');
```

ID Generator
------------

[](#id-generator)

By default, a token ID is an ULID, created by [`Str::ulid()`](https://laravel.com/docs/11.x/strings#method-str-ulid). You can change it for anything by using the `as()` method at runtime. It accepts a string, or a Closure that returns a string.

```
use Laragear\TokenAction\Facades\Token;
use Illuminate\Support\Str;

$token = Token::store('redis')->as(Str::random(32))->until(60);
```

Alternatively, you may use the `Token::$generator` static property the `boot()` method of your `AppServiceProvider` with a Closure that returns a random string.

```
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laragear\TokenAction\Token;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Token::$generator = fn() => Str::random(48);
    }
}
```

Note

The string to generate will be [prefixed](#cache) to avoid cache key collisions.

Configuration
-------------

[](#configuration)

To further configure the package, publish the configuration file:

```
php artisan vendor:publish --provider="Laragear\TokenAction\TokenActionServiceProvider" --tag="config"
```

You will receive the `config/token-action.php` config file with the following contents:

```
return [
    'default' => env('TOKEN_ACTION_STORE'),
    'prefix' => env('TOKEN_ACTION_PREFIX', 'token-action'),
    'middleware' => [
        'validate' => 'token.validate',
        'consume' => 'token.consume',
    ],
    'bound' => 'token',
]
```

### Cache

[](#cache)

```
return [
    'default' => env('TOKEN_ACTION_STORE'),
    'prefix' => env('TOKEN_ACTION_PREFIX', 'token-action'),
```

The `default` key sets which cache store from the application to use. When it's not set, it will use the default set in the application, which on fresh installations is `file`.

The `prefix` keys is the string used to prefix all keys for the Tokens generated by library.

Instead of changing these values directly in the configuration file, you should use the `TOKEN_ACTION_STORE` and `TOKEN_ACTION_PREFIX` environment variables, respectively.

```
TOKEN_ACTION_STORE=memcache
TOKEN_ACTION_PREFIX=my-custom-prefix
```

Important

Ensure you set a fault-tolerant and persistent cache for your Tokens. Using a volatile cache store will prune old tokens even if these should still be valid. A good option is the `file` store, but you may use `database` for maximum reliability, or `redis` compatible store with [persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/).

### Middleware aliases

[](#middleware-aliases)

```
return [
    'middleware' => [
        'validate' => 'token.validate',
        'consume' => 'token.consume',
    ],
]
```

[Both middleware](#middleware) aliases are configured here. If you have other middleware with the same aliases, you may change them here. Alternatively, you can always set the middleware in your route by pointing the middleware class.

```
use Illuminate\Support\Facades\Route;
use Laragear\TokenAction\Http\Middleware\TokenValidateMiddleware;

Route::get('invite', function () {
    // ...
})->middleware(TokenValidateMiddleware::class)
```

### Route binding key

[](#route-binding-key)

```
return [
    'bound' => 'token',
]
```

This library registers the `token` string as route key to create an instance of `Token` based on the string id received. While this usually doesn't bring problems, you may have already a Model or another library using that route key for its own class. Here you can change it for non-conflicting key, like `tokenAction`.

Laravel Octane Compatibility
----------------------------

[](#laravel-octane-compatibility)

- There only singleton using a stale application instance is the Token Store.
- There are no singletons using a stale config instance.
- There are no singletons using a stale request instance.
- There are no static properties written during a request.

The Token Store, and its Cache Store instance stored inside, are not meant to be changed during the application lifetime.

Apart from that, there should be no problems using this package with Laravel Octane.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

### Token swapping

[](#token-swapping)

Users may swap an invalid token with a valid one in the URL to bypass token verification. To avoid this, you can either:

- Use the [Token payload](#payloads) to validate the data before proceeding.
- Use a [signed route](https://laravel.com/docs/11.x/urls#signed-urls) to avoid changing the URL parameters.

Depending on the action being used with the Token, one could be better than the other. For example, if you expect high request volume, the signed route could be great to not hit the application cache or database. On the other hand, the Token payload can be a great solution if you need complex or private information not suited for a URL Query and always get correct data.

### Store obfuscation

[](#store-obfuscation)

The store name in the URL is not obfuscated, which may show which type of services the application is running under. If this is undesired, the store name can be either encoded or mapped.

License
=======

[](#license)

This specific package version is licensed under the terms of the [MIT License](LICENSE.md), at the time of publishing.

[Laravel](https://laravel.com) is a Trademark of [Taylor Otwell](https://github.com/TaylorOtwell/). Copyright © 2011–2026 Laravel LLC.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance78

Regular maintenance activity

Popularity20

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 94.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~65 days

Recently: every ~100 days

Total

10

Last Release

118d ago

Major Versions

v1.2.2 → 2.x-dev2025-02-17

v2.0.0 → v3.0.02026-03-06

PHP version history (2 changes)v1.0.0PHP ^8.1

v3.0.0PHP ^8.3

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5141911?v=4)[Italo](/maintainers/DarkGhostHunter)[@DarkGhostHunter](https://github.com/DarkGhostHunter)

---

Top Contributors

[![DarkGhostHunter](https://avatars.githubusercontent.com/u/5141911?v=4)](https://github.com/DarkGhostHunter "DarkGhostHunter (16 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

laraveltokenstoken

### Embed Badge

![Health badge](/badges/laragear-token-action/health.svg)

```
[![Health](https://phpackages.com/badges/laragear-token-action/health.svg)](https://phpackages.com/packages/laragear-token-action)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M129](/packages/roots-acorn)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M129](/packages/laravel-pulse)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M186](/packages/laravel-ai)[flarum/core

Delightfully simple forum software.

201.4M2.3k](/packages/flarum-core)[illuminate/queue

The Illuminate Queue package.

21332.6M1.6k](/packages/illuminate-queue)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
