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

Token Builder Laravel Package

shetabit/token-builder

Shetabit Token Builder is a Laravel package for generating unique, customizable tokens and attaching them to Eloquent models. Configure character sets, length, prefixes, and uniqueness rules to create API keys, activation codes, or reference strings with simple, fluent methods.

View on GitHub
Deep Wiki
Context7

Getting Started

This package issues unique, opaque tokens for any Eloquent model (API keys, invite codes, password-reset links, short URLs) and later resolves a token string back to its owning model.

  1. Install and publish

    composer require shetabit/token-builder
    php artisan vendor:publish --tag="token-builder-config"
    php artisan vendor:publish --tag="token-builder-migrations"
    php artisan migrate
    
  2. Where to look first

    • config/token-builder.php — token length, allowed characters, prefix, expiry/lifetime, and the bound Token model class. This is the file you will touch most.
    • The published migration — confirm the token column is unique and indexed, and that a nullable expires_at exists.
    • The package Token model — it holds the polymorphic tokenable relation and the expiry/validity helpers.
  3. First use case — issue a token

    use Shetabit\TokenBuilder\Facade\TokenBuilder;
    
    $token = TokenBuilder::model($user)->create();
    // persist/send $token->token to the client
    

    Then resolve it on the way back in:

    $token = TokenBuilder::token($request->bearerToken())->find(); // null when invalid/expired
    

    If the package registers a tokens() morph relation on the tokenable model, $user->tokens gives you the inverse for free.

Implementation Patterns

Issue-on-login / issue-on-registration. Generate the token inside the auth flow and return it once in the response body. Treat it like a password: it is a bearer credential, so never log it and never put it in a URL you don't control.

Resolve in middleware. Wrap TokenBuilder::token(...)->find() in a small middleware or a guard, resolve the owning model, and Auth::setUser($model) — this lets you reuse Laravel's authorization layer instead of hand-rolling checks.

The v4 headline feature: enumerate a model's valid tokens without knowing the token string. Previously tokens were write-only from the app's perspective — you could only look one up if the client presented it. v4 lets you query a model's valid (non-expired, non-revoked) tokens directly, which unlocks:

  • "Active sessions / devices" pages that list, label, and individually revoke credentials.
  • Admin dashboards showing how many live tokens a customer holds.
  • Scheduled pruning that only touches expired rows, and audits that flag models with an unexpectedly high token count.
  • Rotation flows: issue a new token, list existing ones, revoke the stale ones — all without the plaintext token in hand.

Guard against token sprawl. Decide the policy up front: one token per model, or many (one per device). If it's one, revoke the previous token inside the same transaction as the new one is created.

Prune on a schedule. Expired rows accumulate in the tokens table. Add a scheduled command (or model prune-ing) that deletes rows past expires_at; the v4 listing API makes it cheap to check what's still live.

Custom Token model. If you need extra columns (name, last_used_at, user agent, IP), extend the package model, point the config at your class, and add the columns via your own migration. This is the intended extension point and keeps you off the package's internals.

Testing. Use Carbon::setTestNow() to exercise expiry boundaries rather than sleeping, and assertDatabaseHas on the token table to verify issuance. For HTTP tests, issue a token in setUp and pass it as a bearer header.

Gotchas and Tips

  • v4 is a major bump. Even though the changelog only advertises the token-listing feature, a major version can change method signatures, return types (e.g. a single token vs. a collection), config keys, or the underlying schema. Read the v3.0.0...v4.0.0 diff before upgrading, re-publish the config and migration, and run your token tests. Do not assume a drop-in upgrade.
  • Plaintext storage. By default these tokens are typically stored as-is. Anyone with read access to the tokens table has working credentials. If that's unacceptable, hash on write and hash the incoming token before lookup — but note that hashing breaks the plaintext-based listing feature, so plan the trade-off deliberately.
  • Index the lookup column. Every authenticated request does a where token = ?. Confirm the unique index actually exists in the published migration; a table scan here is a silent performance cliff.
  • Collation and case. Lookups are subject to the column's collation. A case-insensitive collation makes tokens case-insensitive (weakening entropy and occasionally surprising you). Store tokens as varbinary/ascii_bin, or at minimum know which behaviour you have.
  • expires_at null semantics. Null almost always means "never expires" — verify in the package's validity check, and be explicit in your own code so a config change can't silently make tokens immortal.
  • Timezone drift. expires_at comparisons use the app timezone against a DB-stored timestamp. Keep config('app.timezone') and the DB session timezone aligned, or short-lived tokens will expire early/late.
  • Ambiguity in listing. If the v4 listing method returns all tokens rather than only valid ones, filter explicitly (where expires_at null or > now) — don't assume the name matches the behaviour.
  • Length and collision. Longer tokens cost nothing; short ones will eventually collide. Let the unique constraint fail loudly in tests rather than silently overwriting.
  • Cascade deletes. If the migration lacks onDelete('cascade') on the morph relation, deleting a user orphans their tokens. Check it, and if it's missing, clean up in a model observer.
  • Error messages. An invalid token and an expired token should return the same response to the client. Distinguishing them hands an attacker a free signal about which tokens once existed.
  • Debugging lookups. When a token "doesn't work", check in this order: the exact string received (whitespace, Bearer prefix stripped?), the row exists, the row isn't expired, the tokenable model still exists. Nine times out of ten it's a stale row from a soft-deleted parent.
  • Revocation. Listing tokens is only half the story — make sure your delete/revoke path is tested, including the case where a user revokes the token they're currently using.
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