NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Refresh Tokens for Laravel

The RefreshTokens facade

RoundlyConsulting\RefreshTokens\Facades\RefreshTokens (alias RefreshTokens) is the recommended entry point. Token verbs sit flat on the facade; everything about one owner’s sessions hangs off sessions($owner), and one row you already hold off session($row):

use RoundlyConsulting\RefreshTokens\Facades\RefreshTokens;

RefreshTokens::for($user)->fromRequest($request)->linkedTo($jti)->issue(); // fluent issue
RefreshTokens::issue($user, new IssueContext(/* … */));                    // the same, as a DTO
RefreshTokens::redeem($plain, ownerType: $morph);   // ?RedemptionResult
RefreshTokens::rotate($plain, new RotationContext(/* … */)); // ?RotationResult
RefreshTokens::revoke($plain);                      // bool — logout with the token in hand
RefreshTokens::prune(days: 7);                      // int — force-delete dead rows

RefreshTokens::sessions($user)->all();              // active sessions, newest first
RefreshTokens::sessions($user)->find($familyId);    // ?RefreshToken
RefreshTokens::sessions($user)->revoke($familyId, RevocationReason::Logout); // bool
RefreshTokens::sessions($user)->revokeOthers($currentJti);      // int
RefreshTokens::sessions($user)->revokeAllExcept($keepFamilyId); // int
RefreshTokens::sessions($user)->revokeAll();                    // int

RefreshTokens::session($row)->enrich($device, $location); // row model or its key
RefreshTokens::session($row)->revoke(RevocationReason::Manual); // bool

Method reference

MethodReturnsWhat it does
for($owner)PendingIssueFluent issue builder; ->issue() calls issue().
issue($owner, IssueContext $context)NewRefreshTokenIssue a token; the plaintext is returned once.
redeem($plain, ?string $ownerType = null)?RedemptionResultAtomically claim a token; every failure is null.
rotate($plain, ?RotationContext $context = null)?RotationResultRedeem and issue a same-family replacement in one call.
revoke($plain, $reason = Logout)boolLogout with the token in hand; true when it ended a live session. A spent token ends the session it was rotated into.
sessions($owner)OwnerSessionsOne owner’s sessions — list, find and revoke by family id.
session($row)SessionHandleOne row (the model or its key) — enrich or revoke it.
prune(?int $days = null)intForce-delete dead rows; returns the count deleted.
fake()RefreshTokensFakeSwap in the recording fake — see Testing.

The sessions() and session() handles

MethodReturnsNotes
sessions($owner)->all()Collection<RefreshToken>Active rows, newest first.
sessions($owner)->find($familyId)?RefreshTokenThe active row of that family; null for a malformed id or another owner’s family.
sessions($owner)->revoke($familyId, $reason)boolRevokes every active row of the family (default Logout); false when nothing was active.
sessions($owner)->revokeAllExcept($keepFamilyId, $reason)intKeeps one session by family id (default LogoutAll); null or an unrecognisable id revokes everything.
sessions($owner)->revokeOthers($currentAccessReference, $reason)intKeeps the session holding that access reference (default LogoutAll); null revokes everything.
sessions($owner)->revokeAll($reason)intRevokes every session (default LogoutAll).
session($row)->enrich($device, $location)voidWrites host-supplied device and geo data onto one row (the model or its key).
session($row)->revoke($reason)boolRevokes one row you hold (default Manual).

sessions($owner) is owner-scoped — another owner’s family, including one of a same-id owner of another type, is unknown to it. session() accepts the RefreshToken model, an int or a string key; an unknown key throws SessionNotFoundException. The verbs on the HasRefreshTokens trait delegate to the same manager — see Sessions.

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 crypto

By 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.