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

Admin Auth Laravel Package

dejwcake/admin-auth

Admin authentication for Laravel. Adds a dedicated admin guard with login, logout, and password handling, plus middleware to protect admin-only routes. Keeps admin sessions separate from regular user sessions so back-office access stays isolated, simple to configure, and easy to drop into existing a...

View on GitHub
Deep Wiki
Context7

Getting Started

Two independent things live in this package: the ApplyUserLocale middleware that reads the authenticated user's language attribute and calls app()->setLocale(), and (as of 2.1.0) a hard dependency on spatie/laravel-permission ^8.3. Start with the middleware, then deal with the dependency.

  1. Install and register. Add the middleware to the web group in bootstrap/app.php (Laravel 11+) or app/Http/Kernel.php, after StartSession and after your auth middleware so $request->user() is populated.
  2. Add the column. Persist a language attribute on your users table (typically a string(5) holding an ISO code like en or pt_BR), and add it to $fillable so profile forms can update it.
  3. Look first at the middleware itself. It is small; read it before writing config. Confirm which attribute name it reads (language) and what it does when the attribute is null — you need to know whether it leaves the app default intact or resets it.
  4. First use case: a user switches language in their profile, the value is saved, and their next request renders translations in that locale. Verify by hitting a page with __('messages.greeting') and checking the output flips after saving the preference.
  5. Upgrading to 2.1.0? Do the dependency work first. Run composer require spatie/laravel-permission:^8.3, resolve any conflicts from other packages still pinning ^7, run your migrations and full test suite, and only then re-verify the locale behaviour. The middleware code is unchanged in 2.1.0, but your app's permission layer now moves with it.

Implementation Patterns

Enum casts (2.0.4+). If you model languages as a PHP enum with a backed string, cast it on the model:

protected function casts(): array
{
    return ['language' => Language::class];
}

Before 2.0.4 this passed the enum object straight into setLocale() and blew up (or silently misbehaved). Now the middleware detects a non-string value and skips it. That means the enum cast works only if the middleware itself unwraps it — if it doesn't, you'll get the app default instead of the user's choice. Test this explicitly after upgrading.

String column, resolve at the edge. The most predictable pattern is to keep language a plain string and validate it against an allowlist in a FormRequest. Store canonical codes only; do the enum conversion in the UI layer, not the persistence layer. This sidesteps the non-string question entirely — and, usefully in 2.1.0, it also matches the BackedEnum|string shape Spatie now expects at its own boundaries.

Ordering with other locale sources. Middleware order defines precedence. A common setup: route-prefix locale (/{locale}/...) wins, then user preference, then config('app.locale'). If you want user preference to win, register ApplyUserLocale after the route-locale middleware; if route should win, reverse it. Don't rely on the package to arbitrate — be explicit.

Per-request only. setLocale() is request-scoped. Anything that runs outside the HTTP stack (queued jobs, artisan commands, scheduler) falls back to config('app.locale'). In jobs that generate user-facing text (emails, notifications), call app()->setLocale($user->language) yourself at the top of handle().

Blade and validation. Once the locale is set, __(), @lang, and validation messages resolve automatically. Publish Laravel's lang/ directory (php artisan lang:publish) and keep translation keys complete — a missing key renders the raw key, which looks broken in a language you don't read yourself.

Permission upgrade (2.1.0). This package ships no code for the Spatie bump, so the upgrade is entirely yours to sequence:

composer require spatie/laravel-permission:^8.3
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="permission-migrations"
php artisan migrate
php artisan optimize:clear

If your composer.json pins ^7.4 directly, update that constraint too — otherwise Composer will happily leave you on v7 while the lockfile disagrees with the package's requirement. If you implement the Role / Permission contracts yourself (custom models or a custom Role class), you must widen the signatures to findByName(BackedEnum|string $name, ?string $guardName = null) and findOrCreate(BackedEnum|string $name, ?string $guardName = null) — PHP will fatal on the interface mismatch otherwise. If you just use Spatie's shipped models, nothing to change. Where you do write role/permission lookups, prefer passing your enum directly now instead of calling ->value at every call site.

Testing the bump. Add a test that assigns a role via the enum path and one that assigns via a string, and assert hasRole() for both. That catches the contract mismatch and any caching-regression from the v8 upgrade in one shot.

Gotchas and Tips

  • Non-string values are ignored silently. Post-2.0.4, if language is an enum, an int, or an array, you get no exception — just the fallback locale. That trades a crash for a quiet regression. Add an assertion in your test suite that a user with a non-default language actually sees non-default output; don't assume the middleware did its job because nothing threw.
  • Authentication ordering. Placing the middleware before auth means $request->user() is null and nothing happens. Placing it inside the web group but in a route that uses a different guard means the wrong user (or none) is read.
  • Guests. Decide deliberately what happens for unauthenticated requests. Browser Accept-Language negotiation, if you want it, is yours to add — this middleware is about the stored user preference.
  • Caching. Locale-aware response caching is a classic bug source. If you cache rendered HTML, vary the cache key on the resolved locale, or you'll serve one user's language to everyone.
  • Date and number formatting. setLocale() covers translations, but Carbon and NumberFormatter need their own attention — set Carbon::setLocale() alongside, and check PHP's intl extension is installed on the target environment if you use NumberFormatter.
  • Missing translation files. The middleware won't warn you about a locale with no corresponding lang/{locale} directory; Laravel just falls through to the fallback locale per-key. Keep the allowlist of storable languages in sync with the directories that actually exist.
  • 2.1.0 is a coordinated upgrade, not a drop-in. The release notes say "no code changes in this package", which is true but misleading: the transitive constraint moved a major version. Budget time for the Spatie upgrade, clear config/route/permission caches after deploying, and deploy the constraint change in the same commit as the lockfile bump so no environment ends up mid-upgrade.
  • Custom contract implementations are the sharp edge. Widening a parameter type in an interface is technically a BC break for implementors. If you have your own Role or Permission model, the failure mode is a PHP fatal at autoload/reflect time — noisy, at least. Grep for implements.*Role and implements.*Permission before you deploy.
  • Dist archives are leaner. If you composer require this package and then go looking for its tests to understand edge-case behaviour (especially the enum path), they aren't there — .gitattributes export-ignores tests, Docker, and QA config, and 2.1.0 removed a stale phpmd.xml entry from that list without restoring anything. Clone the repository from source if you need to read the test suite.
  • Extension point. If your locale resolution is more complex than "read one attribute" (tenant default, A/B rollout, regional variants), don't fork the package. Wrap it: put your own middleware before it that normalises whatever source you have into $user->language — or set the locale yourself and drop the middleware.
  • Contributing? AGENTS.md/CLAUDE.md were added upstream in 2.0.4 and describe the dev setup (MariaDB 12.3, Testbench). They exist only in the source repo, not in the dist archive — same as the tests.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource