Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tokenable Laravel Package

jundayw/tokenable

jundayw/tokenable is a Laravel package that adds token support to Eloquent models, helping you generate and manage tokens for authentication or access control. A lightweight helper for token-based APIs and PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require jundayw/tokenable
php artisan vendor:publish --provider="Jundayw\Tokenable\TokenableServiceProvider"
php artisan migrate

Start by reading these, in order:

  1. vendor/jundayw/tokenable/README.md — the only usage documentation.
  2. config/tokenable.php (or whatever the published config is named) — token table, TTLs, guard names.
  3. src/ — especially traits, the token model, middleware, and the service provider. With a 2-star package, the source is the documentation.
  4. database/migrations/ — confirm the table name and columns before migrating into an existing schema.

Add the package trait to every authenticatable model you want to issue tokens for:

use Jundayw\Tokenable\Traits\HasTokenable; // confirm exact namespace in src/

class User extends Authenticatable
{
    use HasTokenable;
}

The first end-to-end use case is a single API login that returns an access token and a refresh token, plus one protected route:

Route::post('/login', function (Request $request) {
    $user = User::where('email', $request->email)->firstOrFail();

    // Method names are indicative — verify against the trait.
    $token = $user->createToken('api');

    return response()->json([
        'access_token'  => $token->plainTextToken,
        'refresh_token' => $token->refreshToken ?? null,
    ]);
});

Route::middleware('auth:api')->get('/me', fn (Request $request) => $request->user());

Register the package's guard/middleware in config/auth.php and bootstrap/app.php (Laravel 11+) or Kernel.php before testing. If the README does not show the guard driver name, search the source for Auth::extend / Auth::viaRequest.

Implementation Patterns

Login controller pattern. Keep token issuance in a small action or service, not scattered across controllers. Validate credentials first, then issue tokens. Return the plain-text token exactly once; only the hash should be persisted.

final class IssueToken
{
    public function __invoke(User $user, string $platform = 'api'): array
    {
        $access  = $user->createToken($platform);
        $refresh = $user->createRefreshToken($platform); // indicative

        return [
            'token_type'   => 'Bearer',
            'access_token' => $access->plainTextToken,
            'expires_in'   => config('tokenable.access_ttl'),
            'refresh_token'=> $refresh->plainTextToken,
        ];
    }
}

Route protection. Apply the package middleware to API route groups rather than individual routes, and keep a separate group for unauthenticated auth endpoints:

Route::post('/login', [AuthController::class, 'login']);
Route::post('/refresh', [AuthController::class, 'refresh']);

Route::middleware(['auth:api'])->group(function () {
    Route::get('/me', [AuthController::class, 'me']);
});

Multi-model support. The value of this package is that tokens are polymorphic. Use it when you have User, Admin, and Partner models that all need API credentials. Give each model its own guard in config/auth.php with the correct provider, otherwise auth:api will resolve the wrong model:

'guards' => [
    'api'   => ['driver' => 'tokenable', 'provider' => 'users'],
    'admin' => ['driver' => 'tokenable', 'provider' => 'admins'],
],

Multi-platform tokens. Issue one token per platform/device and store the platform label. This lets you revoke “all web sessions” without touching mobile sessions:

$user->createToken('web');
$user->createToken('ios');
$user->createToken('ssr');

// Later:
$user->tokens()->where('platform', 'web')->delete();

Confirm whether the package stores platform on the token row or expects you to use token names. If it does not store device metadata, add a nullable platform column via your own migration.

Refresh-token rotation. Access tokens should be short-lived (5–15 minutes); refresh tokens long-lived. On refresh, revoke the presented refresh token and issue a new pair. This limits replay damage if a refresh token leaks:

public function refresh(Request $request)
{
    $user = $request->user(); // resolved from refresh token

    $request->token->delete(); // revoke used refresh token
    return $this->issue($user, $request->token->platform);
}

If the package does not support rotation natively, wrap it in your own endpoint and treat the refresh token as a one-time credential.

SPA vs API vs SSR. For SPAs, prefer an HttpOnly cookie carrying the refresh token and a short-lived bearer access token in memory. For SSR, set the access token in an HttpOnly cookie and let the package guard read it, avoiding token exposure in HTML. For pure APIs, use Authorization: Bearer. Do not mix cookies and bearer tokens on the same route group without CSRF protection.

Cleanup and observability. Schedule pruning of expired and revoked tokens:

Schedule::command('tokenable:prune')->daily(); // confirm command name

Log token issuance and revocation events with user ID and platform. Since refresh tokens are long-lived credentials, an audit trail is useful when debugging “why was this session logged out.”

Testing. Custom guards often bypass Laravel's actingAs(). For feature tests, obtain a real token via the login endpoint or use the package's token factory if one exists. Add a test that asserts a revoked token returns 401 and an expired token returns 401.

Gotchas and Tips

  • Low adoption is the primary risk. Two stars and zero dependents means no community answers, no security advisories, and likely stale compatibility. Pin an exact version in composer.json, read the token hashing code yourself, and be prepared to fork. Do not adopt it for a long-lived product without a maintenance plan.
  • The README is probably incomplete. Verify every method name (createToken, createRefreshToken, revoke, etc.) in src/ before writing controllers. The code examples above are indicative, not guaranteed.
  • Table-name collisions. If Sanctum or Passport is also installed, a generic tokens table will conflict. Change the table name in the published config, or remove the competing package.
  • Publish before migrate. Running php artisan migrate before publishing migrations creates an empty or missing schema. Publish config and migrations, inspect them, then migrate.
  • Guard driver registration. A 404 or “auth guard [api] is not defined” error usually means the package's guard driver was not registered or the config was cached. Run php artisan config:clear after editing config/auth.php.
  • Hashed storage. Confirm tokens are stored hashed, not plain text. If the migration stores a plain token column, treat the package as insecure for production and hash before persisting.
  • Expiry units. Check whether TTL config values are seconds or minutes. Off-by-60 errors here produce tokens that expire in 60 minutes instead of 60 seconds, or sessions that die immediately.
  • Refresh-token race conditions. Two parallel refresh requests can both succeed and revoke each other. Use a database transaction and a short lock, or accept that one client request will fail and retry.
  • Polymorphic provider mismatch. With multiple models, auth:api can authenticate an Admin against a User route if providers and guards are misconfigured. Add a guard-per-model and test cross-model access explicitly.
  • Middleware aliases. If the package ships middleware, register the alias in bootstrap/app.php (Laravel 11+) rather than assuming it is auto-discovered.
  • Cache and config. php artisan config:cache freezes the published config. Any guard or TTL change requires a cache clear during deployment.
  • Extension points to look for. Custom token model (extend and rebind in the service provider), token-created/token-revoked events, a configurable hashing strategy, and a prune command. If none exist, wrap the package behind your own TokenService interface so you can replace it later with Sanctum or a hand-rolled implementation.
  • Exit strategy. Because the package is small, isolate it behind one service class and one middleware alias. Migrating to Sanctum later then means rewriting one file, not every controller.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core