Open source
Refresh Tokens for Laravel
composer require roundly-consulting/refresh-tokens-for-laravelOverview
Opaque, rotating refresh tokens and device sessions for Laravel. Tokens are stored only as SHA-256 digests, rotated by a single-query compare-and-swap so exactly one concurrent refresh wins, and replaying a spent token revokes its whole family automatically. Any Authenticatable model — users, API clients, admins — holds sessions in one polymorphic table, with a stable session id, device data and one-call “log out everywhere”. MIT-licensed, with zero third-party runtime dependencies — just Laravel plus Roundly’s own crypto, enums and toolkit packages.
What you get
Hashed at rest
Only a SHA-256 digest is stored under a unique index; the plaintext is returned once. Optional HMAC pepper on top.
Atomic rotation
A single-query compare-and-swap: of N concurrent refreshes exactly one wins — no transaction, no row lock.
Reuse detection
Replaying a rotated token revokes the whole family, denies its access tokens and fires an alert event. Always on.
Device sessions
A stable session id per login, device and geo data, and one-call revoke of one, all others or every session.
Polymorphic owners
Users, API clients, admins — any Authenticatable model shares one table, with guard-scoped redemption.
Sliding + absolute lifetimes
A sliding TTL per rotation plus a hard absolute cap per session, both overridable per login.
Facade, DI or actions
One RefreshTokens facade over an injectable manager and single-purpose actions, plus a recording fake that still runs every call.
Documentation
Installation
Install via Composer, publish and run the migration, and add the HasRefreshTokens trait to every owner model.
Configuration
Every config key, default and env variable — table, key type, lifetimes, token length, hashing, rotation grace and pruning.
Owners & key types
Polymorphic owners: users, API clients and admins share one table, isolated by morph class and key, on bigint, UUID or ULID keys.
The RefreshTokens facade
The whole RefreshTokens facade at a glance — issue, redeem, rotate, revoke and prune, plus the sessions() and session() handles.
DI and actions
Inject RefreshTokensManager instead of calling the facade, or run the action behind any method — the same code either way.
Issuing tokens
Issue a refresh token linked to your access token via IssueContext or the fluent builder; the plaintext is returned exactly once.
Redeeming & rotating
Atomically redeem a token with anti-double-spend, rotate it in one call, scope redemption to one owner type, and handle failures.
Reuse detection
Replaying a rotated token revokes the whole family, denies its access tokens and fires RefreshTokenReuseDetected — always on.
Revocation & logout
Log out one token or every session, record why with RevocationReason, and revoke everything on a password change.
Sessions
List, find and revoke device sessions by their stable family id — the machinery behind a “your devices” screen.
Device & location enrichment
Attach host-parsed browser, OS, device type and geolocation to a session with enrich() — typically from an async job.
Access-token revocation
Bind an AccessTokenRevoker so every revoked session or family also kills its paired access token, e.g. via a JWT jti denylist.
Events
Four typed events — issued, redeemed, revoked and reuse-detected — carrying ids and scalars only, never the model or plaintext.
Security & hashing
SHA-256 digests at rest, an optional HMAC pepper, validated config, serialization safety and the host-owned boundary.
The token model
Scopes, helpers, casts and hidden attributes on the RefreshToken model, and how to swap in your own subclass.
Database schema
The refresh_tokens columns, plus RefreshTokenBlueprint for reproducing or adopting the schema in your own migration.
Artisan commands
Prune dead tokens on your own schedule with refresh-tokens:prune or a named model:prune, and inspect config with about.
Exceptions
Every typed exception the package throws, when it throws, and the base class to catch them all.
Testing
RefreshTokens::fake() records every issue, redeem, rotate, revoke, enrich and prune; FakeAccessTokenRevoker and the factory cover the rest.
Requirements
PHP 8.4+ and Laravel 12 or 13, with zero third-party runtime dependencies. Companion Roundly packages install automatically.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.