illuminate/auth
Illuminate/auth provides Laravel's authentication and authorization services: session guards, user providers, password hashing, gates and policies, and remember-me support. It powers login, registration, and access control out of the box, integrating with Eloquent and middleware to secure routes and...
laravel/framework that Composer publishes for the auth subsystem. In a normal Laravel app you already have it — confirm with composer show illuminate/auth. Only add it to composer.json when you are wiring Illuminate components by hand, and then pin the version to your framework's, or you'll get Illuminate\Contracts mismatches.laravel/breeze (Blade/React/Vue starter scaffolding) or laravel/fortify (headless auth with routes, actions and views decoupled). Both sit on top of this package and give you a working login, register, forgot-password, reset-password, verify-email and confirm-password flow in one command.config/auth.php. Everything day-to-day resolves through the three keys there — defaults.guard, guards (session driver with a provider, or token for static API keys), and providers (eloquent driver pointing at App\Models\User). Second place: Illuminate\Auth\SessionGuard — it is the class that actually implements attempt, login, logout, viaRemember.// routes/web.php
Route::post('/login', function (Request $request) {
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials, $request->boolean('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/dashboard');
}
return back()->withErrors(['email' => 'Invalid credentials.'])->onlyInput('email');
})->middleware('guest');
Route::post('/logout', function (Request $request) {
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
})->middleware('auth');
php artisan route:list --path=login, php artisan about (shows default guard), and Auth::getDefaultDriver() in tinker.web (session) for browser, sanctum for SPA/mobile tokens, api (token driver) for machine clients. Then name it in middleware — auth:web, auth:sanctum — and in code with Auth::guard('sanctum')->user(). If most of your app uses one non-default guard, call Auth::shouldUse('sanctum') in a service provider so Auth::user() and the @auth directive agree.Auth::attempt(...) → $request->session()->regenerate() (Laravel's SessionGuard::login() migrates the session, but regenerate again after your own logic) → redirect with intended(). On failure, never echo why — one generic error keyed on email.attempt vs validate vs once: attempt() logs in and persists to session; validate() only checks credentials (good for pre-flight checks or re-auth before sensitive actions); once() authenticates for the current request only (queue workers, stateless calls). Auth::attemptWhen($creds, fn ($user) => $user->is_active) is the clean way to add an activation gate without a custom guard.User uses Illuminate\Foundation\Auth\User which pulls in Authorizable; that's what makes Gate, Policy, $user->can('update', $post), @can('update', $post), and the can:update,post middleware route work. Keep role checks in policies, not in controllers — Auth::user()->is_admin sprinkled through views is the classic drift.$status = Password::sendResetLink($request->only('email'));
if ($request->filled('token')) {
$status = Password::reset($request->only('email', 'password', 'password_confirmation', 'token'),
function (User $user, string $password) {
$user->forceFill(['password' => Hash::make($password)])->save();
event(new PasswordReset($user));
});
}
Configure passwords.users.expire (minutes) and .throttle (seconds) in config/auth.php, and use Password::broker('admins') when you have a second provider.
Illuminate\Contracts\Auth\MustVerifyEmail on the model and apply the verified middleware (EnsureEmailIsVerified). The contract alone does nothing — the middleware plus the VerificationController/Fortify routes are what enforce it.Login, Logout, Failed, Lockout, Attempting, Authenticated, PasswordReset, Verified are dispatched by the guards and brokers. Audit logging, "last login at" columns and security alerts belong in listeners registered from an EventServiceProvider; that keeps your customizations upgrade-safe.RateLimiter facade in your login controller (Breeze's LoginRequest does exactly this): RateLimiter::tooManyAttempts($key, 5) → RateLimiter::hit($key) → throw a ValidationException with throttle in the message bag. The key is usually Str::lower($email).'|'.$request->ip().AuthManager, registered in a provider's boot(): Auth::extend('jwt', fn ($app, $name, $config) => new JwtGuard(...)) and Auth::provider('ldap', fn ($app, $config) => new LdapUserProvider(...)). Auth::viaRequest('api-token', fn ($request) => ...) is the shortcut when the config is just a closure.laravel/sanctum for first-party SPAs and mobile; laravel/passport when you need full OAuth2 (scopes, refresh tokens, client grants). Both plug into this package's guard contract, so $request->user() and auth:sanctum behave like any other guard.$this->actingAs($user) (or actingAs($user, 'sanctum')) shortcuts the whole guard stack. For login-flow tests, assert on the real thing — $this->post('/login', [...])->assertAuthenticatedAs($user) — and use Event::fake([Login::class]) + Event::assertDispatched when the point of the test is the side effect.Auth::login($user) (optionally Auth::guard('web')->login($user)) — but stash the original id in session and add an explicit exit route, or support will have a bad day.illuminate/auth to a Laravel app's composer.json. It's a split of the framework; a version skew between it and laravel/framework produces confusing Class not found or contract-signature errors. If it's already listed, remove it and let the framework supply it.Auth::user() returns null silently. Either gate with Auth::check(), type-hint Request $request and use $request->user(), or put auth middleware on the route. Null-property errors on a protected page almost always mean the middleware was never applied (or a different guard resolved it).user() null" cause. auth:sanctum in the route but Auth::guard('web')->user() in the controller gives you two different users. Check Auth::getDefaultDriver() and log Auth::guard()->getName() while debugging.Auth::attempt() returning true yet the next request being anonymous means the session isn't persisting — missing StartSession/web middleware group, session driver set to array, or a mismatched SESSION_DOMAIN/SESSION_COOKIE for the SPA domain.Auth::attempt(['email' => ..., 'password' => ..., 'tenant_id' => 3]) adds where tenant_id = 3 to the user lookup. That's a feature, but a typo'd key (emails) turns into an unknown column or worse, an always-failing login.getAuthPassword() expects (password by default) and the provider must be eloquent with a model implementing AuthenticatableContract. Any other key is treated as a plain lookup column.remember_token column: Auth::attempt($creds, true) needs a nullable remember_token (100 chars) or the login succeeds and then throws on updateRememberToken(). Auth::viaRemember() tells you a session was resumed from the cookie.Auth::logout() clears the guard; you still need $request->session()->invalidate() and regenerateToken(). Skipping them leaves a fixed session id around.Auth::logoutOtherDevices($password) requires the AuthenticateSession middleware on the routes that should be affected, plus the password re-check. Without the middleware it does nothing observable.Auth::routes() no longer exists (removed in Laravel 8). Any tutorial telling you to add it is wrong — use Breeze, Fortify, or write the routes.auth middleware aliases live in app/Http/Kernel.php on Laravel 10 and below, and in bootstrap/app.php (->withMiddleware(fn ($m) => $m->alias([...]))) on Laravel 11+. A missing alias shows up as "Target class [auth] does not exist".config/auth.php on a deployed app, php artisan config:cache (or config:clear locally) — otherwise a stale guard/provider map sends you chasing ghosts.HASH_DRIVER changed (bcrypt ↔ argon2id) or the rounds value changed, existing users can't log in until rehashed. Laravel's rehash_on_login (Laravel 11+, config/hashing.php) handles this automatically; on older versions add it to your Login listener with Hash::needsRehash($user->getAuthPassword()).Illuminate\Auth\Events\Failed (it carries $credentials and $user) rather than dumping inside the controller; inspect the resolved guard with Auth::guard()->getProvider()->getModel(); confirm providers.users.model points at a class that actually exists in the config cache.Auth::extend, Auth::provider, Auth::viaRequest, custom PasswordBroker subclasses (rebind auth.password in the container), and event listeners. Overriding SessionGuard methods directly means re-merging on every framework bump.can: middleware and @can silently pass for guests on abilities with no policy — always pair with auth middleware, and Gate::define an explicit deny for the unauthenticated case when the ability is security-sensitive.How can I help you explore Laravel packages today?