Navigation

Laravel

How to Add a Custom Guard for Authentication

Create custom Laravel authentication guards for different user types, API authentication, and specialized authentication flows 2025

Table Of Contents

Laravel's Built-in Solution: Custom Guard Configuration

Laravel allows creating custom guards in config/auth.php with different drivers and providers for specialized authentication needs like admin panels or API endpoints.

// config/auth.php - Add custom guards
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    
    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
    
    // Custom admin guard
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],
    
    // Custom API guard for admins
    'admin-api' => [
        'driver' => 'token',
        'provider' => 'admins',
        'hash' => false,
    ],
    
    // JWT guard (requires package)
    'jwt' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
    
    // Custom driver guard
    'custom' => [
        'driver' => 'custom-driver',
        'provider' => 'users',
    ],
],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    
    // Custom admin provider
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],
    
    // Database provider for custom table
    'api_users' => [
        'driver' => 'database',
        'table' => 'api_users',
    ],
],

// Admin model for custom guard
class Admin extends Authenticatable
{
    use HasFactory, Notifiable;
    
    protected $fillable = [
        'name', 'email', 'password',
    ];
    
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
    
    // Define admin-specific methods
    public function isSuperAdmin()
    {
        return $this->role === 'super_admin';
    }
}

// Admin migration
Schema::create('admins', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->string('role')->default('admin');
    $table->rememberToken();
    $table->timestamps();
});

// Admin authentication controller
class AdminAuthController extends Controller
{
    public function showLoginForm()
    {
        return view('admin.auth.login');
    }
    
    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);
        
        if (Auth::guard('admin')->attempt($credentials, $request->boolean('remember'))) {
            $request->session()->regenerate();
            
            return redirect()->intended('/admin/dashboard');
        }
        
        return back()->withErrors([
            'email' => 'The provided credentials do not match our records.',
        ]);
    }
    
    public function logout(Request $request)
    {
        Auth::guard('admin')->logout();
        
        $request->session()->invalidate();
        $request->session()->regenerateToken();
        
        return redirect('/admin/login');
    }
}

// Admin routes with custom guard
Route::prefix('admin')->group(function () {
    Route::get('/login', [AdminAuthController::class, 'showLoginForm'])->name('admin.login');
    Route::post('/login', [AdminAuthController::class, 'login']);
    Route::post('/logout', [AdminAuthController::class, 'logout'])->name('admin.logout');
    
    Route::middleware('auth:admin')->group(function () {
        Route::get('/dashboard', [AdminController::class, 'dashboard'])->name('admin.dashboard');
        Route::resource('/users', AdminUserController::class);
    });
});

// Middleware for admin guard
class AdminMiddleware
{
    public function handle($request, Closure $next)
    {
        if (!Auth::guard('admin')->check()) {
            return redirect()->route('admin.login');
        }
        
        return $next($request);
    }
}

// Register middleware in Kernel.php
protected $routeMiddleware = [
    // ... other middleware
    'admin' => \App\Http\Middleware\AdminMiddleware::class,
];

// Using custom guard in controllers
class AdminController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:admin');
    }
    
    public function dashboard()
    {
        $admin = Auth::guard('admin')->user();
        
        return view('admin.dashboard', compact('admin'));
    }
    
    public function profile()
    {
        // Multiple ways to access admin user
        $admin1 = Auth::guard('admin')->user();
        $admin2 = auth('admin')->user();
        $admin3 = request()->user('admin');
        
        return view('admin.profile', compact('admin1'));
    }
}

// Custom guard driver
class CustomGuard implements Guard
{
    protected $provider;
    protected $user;
    protected $request;
    
    public function __construct(UserProvider $provider, Request $request)
    {
        $this->provider = $provider;
        $this->request = $request;
    }
    
    public function check()
    {
        return !is_null($this->user());
    }
    
    public function guest()
    {
        return !$this->check();
    }
    
    public function user()
    {
        if (!is_null($this->user)) {
            return $this->user;
        }
        
        $token = $this->request->header('X-API-TOKEN');
        
        if ($token) {
            $this->user = $this->provider->retrieveByCredentials([
                'api_token' => hash('sha256', $token)
            ]);
        }
        
        return $this->user;
    }
    
    public function id()
    {
        return $this->user() ? $this->user()->getAuthIdentifier() : null;
    }
    
    public function validate(array $credentials = [])
    {
        if (empty($credentials['api_token'])) {
            return false;
        }
        
        $user = $this->provider->retrieveByCredentials($credentials);
        
        return !is_null($user);
    }
    
    public function hasUser()
    {
        return !is_null($this->user);
    }
    
    public function setUser(Authenticatable $user)
    {
        $this->user = $user;
        
        return $this;
    }
}

// Register custom guard driver
// In AuthServiceProvider
public function boot()
{
    Auth::extend('custom-driver', function ($app, $name, array $config) {
        return new CustomGuard(
            Auth::createUserProvider($config['provider']),
            $app->make('request')
        );
    });
}

// API authentication with custom guard
Route::middleware('auth:api')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user('api');
    });
    
    Route::apiResource('/posts', PostApiController::class);
});

// Multi-guard authentication
class MultiGuardController extends Controller
{
    public function profile(Request $request)
    {
        // Check multiple guards
        if ($user = $request->user('web')) {
            return $this->webUserProfile($user);
        }
        
        if ($admin = $request->user('admin')) {
            return $this->adminProfile($admin);
        }
        
        if ($apiUser = $request->user('api')) {
            return $this->apiUserProfile($apiUser);
        }
        
        return response()->json(['error' => 'Unauthenticated'], 401);
    }
}

// Sanctum integration with custom guards
// config/sanctum.php
'guard' => ['web', 'admin'],

// Use Sanctum with admin guard
Route::middleware('auth:sanctum,admin')->group(function () {
    Route::get('/admin-api/stats', [AdminApiController::class, 'stats']);
});

// Testing custom guards
class CustomGuardTest extends TestCase
{
    public function test_admin_can_login()
    {
        $admin = Admin::factory()->create([
            'email' => 'admin@example.com',
            'password' => Hash::make('password'),
        ]);
        
        $response = $this->post('/admin/login', [
            'email' => 'admin@example.com',
            'password' => 'password',
        ]);
        
        $response->assertRedirect('/admin/dashboard');
        $this->assertTrue(Auth::guard('admin')->check());
    }
    
    public function test_admin_middleware_protects_routes()
    {
        $response = $this->get('/admin/dashboard');
        
        $response->assertRedirect('/admin/login');
    }
    
    public function test_api_guard_with_token()
    {
        $user = User::factory()->create([
            'api_token' => hash('sha256', 'test-token'),
        ]);
        
        $response = $this->withHeader('Authorization', 'Bearer test-token')
                         ->getJson('/api/user');
        
        $response->assertStatus(200);
        $response->assertJson(['id' => $user->id]);
    }
}

// Guard helper methods
class GuardHelper
{
    public static function getCurrentGuard()
    {
        foreach (config('auth.guards') as $guard => $config) {
            if (Auth::guard($guard)->check()) {
                return $guard;
            }
        }
        
        return null;
    }
    
    public static function getCurrentUser()
    {
        $guard = self::getCurrentGuard();
        
        return $guard ? Auth::guard($guard)->user() : null;
    }
}

// Blade directives for custom guards
// In AppServiceProvider
public function boot()
{
    Blade::if('admin', function () {
        return Auth::guard('admin')->check();
    });
    
    Blade::if('superadmin', function () {
        return Auth::guard('admin')->check() && 
               Auth::guard('admin')->user()->isSuperAdmin();
    });
}

// Usage in Blade templates
@admin
    <p>Welcome, Admin {{ auth('admin')->user()->name }}!</p>
@endadmin

@superadmin
    <a href="/admin/system">System Settings</a>
@endsuperadmin

// Multiple authentication forms
{{-- Regular user login --}}
<form method="POST" action="{{ route('login') }}">
    @csrf
    {{-- form fields --}}
</form>

{{-- Admin login --}}
<form method="POST" action="{{ route('admin.login') }}">
    @csrf
    {{-- form fields --}}
</form>

// JWT guard implementation (with tymon/jwt-auth)
// config/auth.php
'jwt' => [
    'driver' => 'jwt',
    'provider' => 'users',
],

// JWT controller
class JWTAuthController extends Controller
{
    public function login(Request $request)
    {
        $credentials = $request->only('email', 'password');
        
        if (!$token = Auth::guard('jwt')->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }
        
        return response()->json(['token' => $token]);
    }
    
    public function me()
    {
        return response()->json(Auth::guard('jwt')->user());
    }
    
    public function logout()
    {
        Auth::guard('jwt')->logout();
        
        return response()->json(['message' => 'Successfully logged out']);
    }
}

// Console commands with guards
class CreateAdminCommand extends Command
{
    protected $signature = 'admin:create {email} {name} {password}';
    
    public function handle()
    {
        Admin::create([
            'email' => $this->argument('email'),
            'name' => $this->argument('name'),
            'password' => Hash::make($this->argument('password')),
        ]);
        
        $this->info('Admin created successfully');
    }
}

// Guard-specific policies
class AdminPostPolicy
{
    public function view(Admin $admin, Post $post)
    {
        return true; // Admins can view all posts
    }
    
    public function delete(Admin $admin, Post $post)
    {
        return $admin->isSuperAdmin();
    }
}

// Register policies for different guards
// In AuthServiceProvider
protected $policies = [
    Post::class => [
        'admin' => AdminPostPolicy::class,
        'web' => PostPolicy::class,
    ],
];

Custom Guard Implementation in Laravel 11

Define custom guards in config/auth.php with specific drivers and providers. Create dedicated models, controllers, and middleware for each authentication context like admin panels or API endpoints.

In Laravel 8 through 11, guards provide isolation between different user types and authentication methods. Use custom providers for different database tables or authentication sources.

Common use cases: "Admin authentication", "API token authentication", "Multi-tenant systems", "External authentication providers". Always implement proper middleware and route protection for each guard.

Alternative approaches include using Laravel Sanctum for unified authentication, implementing OAuth2 servers for third-party integration, or using external authentication services like Auth0 or Firebase.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Laravel