Master Laravel Authentication: From Scaffold to Custom Guard
This guide walks you through Laravel's built‑in authentication scaffolding, database requirements, route and view generation, customizing redirects, usernames, guards, validation, and storage, plus advanced techniques like manual authentication, HTTP basic auth, custom guards, and user providers, all with clear code examples.
Overview
Laravel ships with a complete authentication system that can be scaffolded with a single Artisan command. Run the following on a fresh Laravel installation:
php artisan make:auth
php artisan migrateThese commands generate the authentication routes, controllers, views, and the required database tables. The main configuration lives in config/auth.php, where you define guards (how a request is authenticated) and providers (how user records are retrieved).
Database considerations
The default App\User model uses the users table. Ensure the table includes:
A password column capable of storing a 60‑character bcrypt hash.
A remember_token column (nullable string, length 100) for the "remember me" feature.
Scaffolded authentication
Running php artisan make:auth creates the following controller classes in the App\Http\Controllers\Auth namespace: RegisterController – handles user registration. LoginController – handles login attempts. ForgotPasswordController – sends password‑reset links. ResetPasswordController – processes password resets.
All controllers use Laravel traits to provide the necessary methods, so they usually require no modification.
Routes and views
The command adds authentication routes to routes/web.php and creates the view files under resources/views/auth and a base layout under resources/views/layouts. The views are built with Bootstrap but can be customized.
Customising the flow
Redirect after login/registration
By default users are redirected to /home. Override the protected $redirectTo property or define a redirectTo() method in LoginController, RegisterController or ResetPasswordController to change the destination:
protected $redirectTo = '/dashboard';
// or
protected function redirectTo()
{
return '/custom-path';
}Using a different username field
Laravel authenticates using the email column. To use another column (e.g., username), add a username() method to LoginController:
public function username()
{
return 'username';
}Custom guard
If you need a specific guard for authentication, implement a guard() method in the relevant controller:
use Illuminate\Support\Facades\Auth;
protected function guard()
{
return Auth::guard('admin');
}Changing validation or storage logic
Modify the validator() method to adjust registration rules and the create() method to customise how a new App\User record is persisted.
Working with the authenticated user
Retrieve the current user via the Auth facade:
use Illuminate\Support\Facades\Auth;
$user = Auth::user(); // full user model
$id = Auth::id(); // primary keyWhen a controller method type‑hints Illuminate\Http\Request, you can also call $request->user() to obtain the authenticated instance.
Check whether a request is authenticated:
if (Auth::check()) {
// user is logged in
}Protecting routes
Apply the auth middleware to routes or controllers:
Route::get('profile', function () {
// only authenticated users can access
})->middleware('auth');In a controller you may place the middleware in the constructor:
public function __construct()
{
$this->middleware('auth');
}To use a specific guard, append its name (e.g., auth:api) when attaching the middleware.
If the middleware detects an unauthenticated request, it returns a 401 JSON response for AJAX calls or redirects to the login route. You can customise this behaviour by overriding the unauthenticated() method in app/Exceptions/Handler.php.
Login throttling
LoginControlleruses the Illuminate\Foundation\Auth\ThrottlesLogins trait. After a configurable number of failed attempts, the user is locked out for one minute based on the username/email and IP address.
Manual authentication
If you prefer not to use the scaffolded controllers, you can call the Auth facade directly:
use Illuminate\Support\Facades\Auth;
if (Auth::attempt(['email' => $email, 'password' => $password])) {
return redirect()->intended('dashboard');
}The attempt method accepts an associative array of credentials. It automatically hashes the supplied password before comparing it with the stored hash. It returns true on success, false otherwise.
You may add extra constraints, for example only allowing active users:
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// authenticated and active
}Authenticate against a specific guard:
if (Auth::guard('admin')->attempt($credentials)) {
// admin guard authenticated
}Log the user out:
Auth::logout();Remember‑me functionality
Pass true as the second argument to attempt to set a persistent "remember me" cookie. The users table must contain a remember_token column.
Auth::attempt(['email' => $email, 'password' => $password], true);
if (Auth::viaRemember()) {
// session was created via remember cookie
}Other authentication helpers
Auth::login($user)– log in an already‑retrieved user instance (optionally Auth::login($user, true) to remember). Auth::loginUsingId(1) – authenticate by primary key. Auth::once($credentials) – authenticate for the current request only (stateless, no session or cookies).
HTTP Basic authentication
Attach the auth.basic middleware to a route to trigger the browser's basic‑auth dialog. By default the email column is used as the username.
Route::get('profile', function () {
// protected content
})->middleware('auth.basic');If you are running PHP under FastCGI, add the following lines to .htaccess so the Authorization header is passed correctly:
RewriteCond %{HTTP:Authorization} ^(.*)$
RewriteRule . - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]Stateless basic authentication
Create a custom middleware that calls Auth::onceBasic(). If the method returns a response (e.g., a 401), abort; otherwise continue to the next request handler:
namespace Illuminate\Auth\Middleware;
use Illuminate\Support\Facades\Auth;
class AuthenticateOnceWithBasicAuth
{
public function handle($request, $next)
{
return Auth::onceBasic() ?: $next($request);
}
}Register the middleware and apply it, e.g., ->middleware('auth.basic.once').
Adding a custom guard
Define a new guard in a service provider using Auth::extend. Example for a JWT guard:
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->registerPolicies();
Auth::extend('jwt', function ($app, $name, array $config) {
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}Reference the guard in config/auth.php:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],Request‑closure guard
For simple token‑based authentication you can register a closure guard with Auth::viaRequest:
use App\User;
use Illuminate\Support\Facades\Auth;
public function boot()
{
$this->registerPolicies();
Auth::viaRequest('custom-token', function ($request) {
return User::where('token', $request->token)->first();
});
}Then reference the guard in config/auth.php:
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],Adding a custom user provider
If your user data lives outside a relational database, register a custom provider with Auth::provider:
namespace App\Providers;
use App\Extensions\RiakUserProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->registerPolicies();
Auth::provider('riak', function ($app, array $config) {
return new RiakUserProvider($app->make('riak.connection'));
});
}
}Configure the provider and guard in config/auth.php:
'providers' => [
'users' => [
'driver' => 'riak',
],
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],UserProvider contract
A custom provider must implement Illuminate\Contracts\Auth\UserProvider, which defines the following methods:
interface UserProvider {
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
}Key responsibilities: retrieveById – fetch a user by its primary key. retrieveByToken – fetch a user using the remember‑token pair. updateRememberToken – store a new remember token. retrieveByCredentials – locate a user record based on the supplied credentials (no password check). validateCredentials – compare the supplied plain password with the stored hash (typically using Hash::check).
Authenticatable contract
The user model must implement Illuminate\Contracts\Auth\Authenticatable:
interface Authenticatable {
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}Laravel's default App\User model already implements this interface; custom models should follow the same method signatures.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Laravel Tech Community
Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
