26th Nov 2025
Authentication is one of the most essential features of any web application. While Laravel provides built-in authentication for users, many web applications require separate admin authentication to protect the backend panel.
In this tutorial, you’ll learn how to create a custom admin authentication system in Laravel 12 using a separate admins table, custom guard, login system (by email or username), and helper functions — step-by-step from setup to login functionality.
This guide is perfect for developers who want to build a professional admin panel with secure and independent authentication logic.
๐งฉ What You’ll Learn
By the end of this tutorial, you’ll be able to:
-
Create an Admin Model and Migration
-
Configure a Custom Guard and Provider for Admins
-
Build an Admin Login Form
-
Create a Custom AuthController for Admin Login
-
Implement Login by Email or Username
-
Use a Helper Function for Authentication Redirects
- Logout
-
Secure Your Admin Panel Routes
๐ Step 1: Create the Admin Model and Migration
First, run the following Artisan command to create your Admin model and its migration file:
php artisan make:model Admin -m
Now, open the migration file created under database/migrations and add the following schema:
Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->string('name', 100);
$table->string('username', 100)->unique();
$table->string('email', 150)->unique();
$table->string('password');
$table->string('phone', 20)->nullable();
$table->string('image')->nullable();
$table->enum('gender', ['male', 'female'])->nullable();
$table->enum('status', ['active', 'inactive'])->default('inactive');
$table->timestamps();
});
Then run the migration:
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Traits\HasRoles;
class Admin extends Authenticatable
{
use HasFactory, Notifiable, HasRoles;
protected $guard = 'admin';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'username',
'email',
'phone',
'password',
'image',
'status'
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
Explanation:
-
Authenticatableis used instead ofModelto enable Laravel’s built-in authentication features. -
HasRolesis included from Spatie Permission Package (optional but useful for role-based permissions). -
$guard = 'admin'tells Laravel to use theadminguard when authenticating this model.
โ๏ธ Step 3: Configure Admin Guard and Provider
Now, let’s register a custom guard and provider for the admin in config/auth.php.
Find the guards and providers arrays and update them like this:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
'admins' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\Admin::class),
],
],
Explanation:
-
The web guard handles normal user authentication.
-
The admin guard is a new guard that will manage admin logins separately using the
adminstable.
๐งญ Step 4: Create Admin Routes
In routes/web.php, define your admin routes:
Route::prefix('admin')->group(function () {
Route::get('login', [AuthController::class, 'login'])->name('admin.login');
Route::post('login/submit', [AuthController::class, 'login_submit'])->name('admin.login.submit')
});
Explanation:
We’re grouping admin routes under the /admin prefix to separate them from frontend routes.
You can later add routes like admin/dashboard, admin/logout, etc.
๐งพ Step 5: Create the Admin Login Form (Blade File)
Here’s a sample Blade template for your login form:
<form method="post" action="{{ route('admin.login.submit') }}">
@csrf
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="default-01">Email or Username*</label>
</div>
<div class="form-control-wrap">
<input type="text"name="email_username" required id="email_username"
value="{{ old('email_username') }}" class="form-control form-control-lg"placeholder="Enter your email address or username">
</div>
<div class="text-danger">
@error('email_username')
{{ $message }}
@enderror
</div>
</div>
<div class="form-group">
<div class="form-label-group">
<label class="form-label" for="password">Password*</label>
<a class="link link-primary link-sm" href="{{ route('admin.forgetpass') }}">Forgot password?</a>
</div>
<div class="form-control-wrap">
<a href="#" class="form-icon form-icon-right passcode-switch lg" data-target="password">
<em class="passcode-icon icon-show icon ni ni-eye"></em>
<em class="passcode-icon icon-hide icon ni ni-eye-off"></em>
</a>
<input type="password"required name="password"
id="password" class="form-control form-control-lg" placeholder="Enter your passcode">
</div>
<div class="text-danger">
@error('password')
{{ $message }}
@enderror
</div>
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign in</button>
</div>
</form>
Tips:
-
You can use Bootstrap or a custom UI like DashLite for a modern admin panel.
-
Use
@csrffor protection against CSRF attacks.
๐งฐ Step 6: Add Helper Function
Create a helper function in app/Helpers/helpers.php (make sure to autoload it via composer.json if not already done):
function check_admin_auth($routeName)
{
if (Auth::guard('admin')->check()) {
return redirect()->route('admin.dashboard');
}
return view($routeName);
}
Purpose:
This helper checks if the admin is already logged in and redirects them to the dashboard if so.
๐ง๐ผ Step 7: Create AuthController
Now create the controller:
php artisan make:controller Admin/AuthController
Then add the following logic:
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function login()
{
return check_admin_auth('adminpanel.auth.login');
}
public function login_submit(Request $request)
{
// Validate input
$request->validate([
'email_username' => 'required',
'password' => 'required',
]);
$credentials = $request->only('email_username', 'password');
// Check if email or username and attempt login
if (filter_var($credentials['email_username'], FILTER_VALIDATE_EMAIL)) {
$authAttempt = Auth::guard('admin')->attempt([
'email' => $credentials['email_username'],
'password' => $credentials['password'],
'status' => 'active'
]);
} else {
$authAttempt = Auth::guard('admin')->attempt([
'username' => $credentials['email_username'],
'password' => $credentials['password'],
'status' => 'active'
]);
}
if ($authAttempt && Auth::guard('admin')->check()) {
$user = Auth::guard('admin')->user();
if (!in_array($user->status, ['inactive', 'suspended'])) {
toastr()->success('Admin login successful.');
return redirect()->intended(route('admin.dashboard'));
}
toastr()->error('Your account is inactive or suspended.');
Auth::guard('admin')->logout();
return redirect()->route('admin.login');
}
toastr()->error('Invalid credentials or account is inactive.');
return redirect()->back();
}
}
Explanation:
-
The controller validates inputs and authenticates using either email or username.
-
Uses
Auth::guard('admin')to authenticate from theadminstable. -
Shows Toastr notifications for login success or failure.
-
Redirects inactive accounts back to the login page.
Step 8: Add Admin Logout Route
In your routes/web.php, inside the admin route group, add this line:
Route::middleware('auth:admin')->prefix('admin')->group(function () {
Route::post('/logout', [AuthController::class, 'logout'])->name('admin.logout');
});
๐ธ The logout route must be a POST request for CSRF protection.
Add Logout Button (in Blade)
Here’s the improved and clean Blade code for your logout dropdown:
<div class="dropdown-inner">
<ul class="link-list">
<li>
<a href="#"
onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
<em class="icon ni ni-signout"></em>
<span>Sign out</span>
</a>
</li>
</ul>
<form id="logout-form" action="{{ route('admin.logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
How it works:
-
When you click Sign out, it prevents the default link action.
-
Then, it submits the hidden form via POST to the
admin.logoutroute.
Add the Logout Logic (Controller)
Your logout function looks great, just make sure it’s inside the same AuthController and under the correct namespace:
public function logout()
{
Auth::guard('admin')->logout(); // โ
ensures admin guard logout
toastr()->success('Admin logged out successfully!');
return redirect()->route('admin.login');
}
Step 8: Protect Admin Routes with Middleware
To restrict access to authenticated admins only, use middleware in routes:
Route::middleware('auth:admin')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('admin.dashboard');
});
This ensures only logged-in admins can access the dashboard.
โ Final Thoughts
Congratulations! ๐
You’ve successfully created a custom admin authentication system in Laravel 12 with a dedicated admins table, separate login, and authentication guard.
This setup helps you maintain a clean separation between user and admin logic, making your application secure, scalable, and professional.
Next Steps
-
Add Password Reset and Email Verification for admins.
-
Integrate Role & Permission using Spatie Laravel Permission.
Leave A Reply
Your email address will not be published. Required fields are marked