Authentication & Authorization: Secure Laravel Applications
Authentication & Authorization: Secure Laravel Applications
Expert Guide by Alaa Amer – Professional Web Developer & Applications Designer
Laravel provides robust authentication and authorization systems. Master security patterns, API protection, and enterprise-level access control for production applications.
2️⃣ Role-Based Access Control (RBAC)
Advanced Permission System:
<?php
// app/Models/Role.php
namespace App\Models;
use Spatie\Permission\Models\Role as SpatieRole;
class Role extends SpatieRole
{
protected $fillable = [
'name', 'guard_name', 'description', 'level', 'is_system'
];
protected $casts = [
'is_system' => 'boolean',
'level' => 'integer'
];
public function users()
{
return $this->belongsToMany(User::class, 'model_has_roles', 'role_id', 'model_id');
}
public function isSystemRole(): bool
{
return $this->is_system;
}
public function canBeDeleted(): bool
{
return !$this->is_system && $this->users()->count() === 0;
}
public function hasHigherLevelThan(Role $role): bool
{
return $this->level > $role->level;
}
}
// app/Models/Permission.php
namespace App\Models;
use Spatie\Permission\Models\Permission as SpatiePermission;
class Permission extends SpatiePermission
{
protected $fillable = [
'name', 'guard_name', 'description', 'category', 'is_system'
];
protected $casts = [
'is_system' => 'boolean'
];
public function scopeByCategory($query, string $category)
{
return $query->where('category', $category);
}
public function getFormattedNameAttribute(): string
{
return ucfirst(str_replace('.', ' ', $this->name));
}
}
// database/seeders/RolePermissionSeeder.php
namespace Database\Seeders;
use App\Models\{Role, Permission, User};
use Illuminate\Database\Seeder;
class RolePermissionSeeder extends Seeder
{
public function run(): void
{
// Create Permissions
$permissions = [
// User Management
['name' => 'users.view', 'category' => 'users', 'description' => 'View users'],
['name' => 'users.create', 'category' => 'users', 'description' => 'Create users'],
['name' => 'users.edit', 'category' => 'users', 'description' => 'Edit users'],
['name' => 'users.delete', 'category' => 'users', 'description' => 'Delete users'],
// Post Management
['name' => 'posts.view', 'category' => 'posts', 'description' => 'View posts'],
['name' => 'posts.create', 'category' => 'posts', 'description' => 'Create posts'],
['name' => 'posts.edit', 'category' => 'posts', 'description' => 'Edit posts'],
['name' => 'posts.delete', 'category' => 'posts', 'description' => 'Delete posts'],
['name' => 'posts.publish', 'category' => 'posts', 'description' => 'Publish posts'],
// System Administration
['name' => 'admin.dashboard', 'category' => 'admin', 'description' => 'Access admin dashboard'],
['name' => 'admin.settings', 'category' => 'admin', 'description' => 'Manage system settings'],
['name' => 'admin.roles', 'category' => 'admin', 'description' => 'Manage roles'],
];
foreach ($permissions as $permission) {
Permission::firstOrCreate(['name' => $permission['name']], $permission);
}
// Create Roles
$roles = [
[
'name' => 'super-admin',
'description' => 'Super Administrator',
'level' => 100,
'is_system' => true,
'permissions' => Permission::all()->pluck('name')->toArray()
],
[
'name' => 'admin',
'description' => 'Administrator',
'level' => 90,
'is_system' => false,
'permissions' => [
'users.view', 'users.create', 'users.edit',
'posts.view', 'posts.create', 'posts.edit', 'posts.delete', 'posts.publish',
'admin.dashboard'
]
],
[
'name' => 'editor',
'description' => 'Content Editor',
'level' => 70,
'is_system' => false,
'permissions' => [
'posts.view', 'posts.create', 'posts.edit', 'posts.publish'
]
],
[
'name' => 'author',
'description' => 'Content Author',
'level' => 50,
'is_system' => false,
'permissions' => [
'posts.view', 'posts.create', 'posts.edit'
]
],
[
'name' => 'user',
'description' => 'Regular User',
'level' => 10,
'is_system' => true,
'permissions' => []
]
];
foreach ($roles as $roleData) {
$permissions = $roleData['permissions'];
unset($roleData['permissions']);
$role = Role::firstOrCreate(['name' => $roleData['name']], $roleData);
$role->syncPermissions($permissions);
}
}
}
Advanced Authorization Middleware:
<?php
// app/Http/Middleware/CheckRole.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckRole
{
public function handle(Request $request, Closure $next, ...$roles)
{
if (!auth()->check()) {
return redirect()->route('login');
}
$user = auth()->user();
// Check if user is locked
if ($user->isLocked()) {
auth()->logout();
return redirect()->route('login')
->withErrors(['account' => 'Your account has been temporarily locked.']);
}
// Check roles
foreach ($roles as $role) {
if ($user->hasRole($role)) {
return $next($request);
}
}
// Log unauthorized access attempt
activity()
->causedBy($user)
->withProperties([
'roles_required' => $roles,
'user_roles' => $user->getRoleNames()->toArray(),
'route' => $request->route()->getName(),
'ip' => $request->ip()
])
->log('unauthorized_access_attempt');
abort(403, 'Insufficient privileges.');
}
}
// app/Http/Middleware/CheckPermission.php
class CheckPermission
{
public function handle(Request $request, Closure $next, string $permission, ?string $guard = null)
{
if (!auth($guard)->check()) {
return $this->handleUnauthenticated($request);
}
$user = auth($guard)->user();
if (!$user->can($permission)) {
return $this->handleUnauthorized($request, $user, $permission);
}
return $next($request);
}
protected function handleUnauthenticated(Request $request)
{
if ($request->expectsJson()) {
return response()->json(['message' => 'Unauthenticated.'], 401);
}
return redirect()->guest(route('login'));
}
protected function handleUnauthorized(Request $request, $user, string $permission)
{
// Log the unauthorized attempt
activity()
->causedBy($user)
->withProperties(['permission' => $permission])
->log('unauthorized_permission_attempt');
if ($request->expectsJson()) {
return response()->json([
'message' => 'This action is unauthorized.',
'required_permission' => $permission
], 403);
}
abort(403);
}
}
4️⃣ Advanced Security Features
Multi-Factor Authentication:
<?php
// app/Http/Controllers/TwoFactorController.php
namespace App\Http\Controllers;
use App\Http\Requests\TwoFactorRequest;
use Illuminate\Http\JsonResponse;
use PragmaRX\Google2FA\Google2FA;
class TwoFactorController extends Controller
{
protected $google2fa;
public function __construct()
{
$this->middleware('auth');
$this->google2fa = new Google2FA();
}
public function enable(): JsonResponse
{
$user = auth()->user();
if ($user->two_factor_confirmed_at) {
return response()->json(['message' => '2FA already enabled'], 400);
}
$secretKey = $user->enableTwoFactor();
$qrCodeUrl = $this->google2fa->getQRCodeUrl(
config('app.name'),
$user->email,
$secretKey
);
return response()->json([
'secret_key' => $secretKey,
'qr_code_url' => $qrCodeUrl,
'recovery_codes' => $this->generateRecoveryCodes($user)
]);
}
public function confirm(TwoFactorRequest $request): JsonResponse
{
$user = auth()->user();
if ($user->confirmTwoFactor($request->code)) {
activity()
->causedBy($user)
->log('two_factor_enabled');
return response()->json(['message' => '2FA enabled successfully']);
}
return response()->json(['message' => 'Invalid code'], 400);
}
public function verify(TwoFactorRequest $request): JsonResponse
{
$user = auth()->user();
// Check 2FA code
if ($this->verifyCode($user, $request->code)) {
session(['2fa_verified' => true]);
return response()->json(['message' => '2FA verification successful']);
}
return response()->json(['message' => 'Invalid 2FA code'], 400);
}
public function disable(TwoFactorRequest $request): JsonResponse
{
$user = auth()->user();
if ($this->verifyCode($user, $request->code)) {
$user->disableTwoFactor();
activity()
->causedBy($user)
->log('two_factor_disabled');
return response()->json(['message' => '2FA disabled successfully']);
}
return response()->json(['message' => 'Invalid code'], 400);
}
protected function verifyCode($user, string $code): bool
{
// Try regular 2FA code
if ($user->two_factor_secret) {
$secret = decrypt($user->two_factor_secret);
if ($this->google2fa->verifyKey($secret, $code)) {
return true;
}
}
// Try recovery codes
$recoveryCodes = json_decode(decrypt($user->two_factor_recovery_codes ?? '[]'), true);
if (in_array($code, $recoveryCodes)) {
// Remove used recovery code
$recoveryCodes = array_diff($recoveryCodes, [$code]);
$user->update([
'two_factor_recovery_codes' => encrypt(json_encode($recoveryCodes))
]);
return true;
}
return false;
}
protected function generateRecoveryCodes($user): array
{
$recoveryCodes = [];
for ($i = 0; $i < 10; $i++) {
$recoveryCodes[] = strtoupper(Str::random(4) . '-' . Str::random(4));
}
$user->update([
'two_factor_recovery_codes' => encrypt(json_encode($recoveryCodes))
]);
return $recoveryCodes;
}
}
// app/Http/Middleware/RequireTwoFactor.php
class RequireTwoFactor
{
public function handle(Request $request, Closure $next)
{
$user = auth()->user();
if ($user && $user->two_factor_confirmed_at && !session('2fa_verified')) {
if ($request->expectsJson()) {
return response()->json(['message' => '2FA verification required'], 403);
}
return redirect()->route('2fa.verify');
}
return $next($request);
}
}
Security Monitoring & Logging:
<?php
// app/Services/SecurityService.php
namespace App\Services;
use App\Models\{SecurityLog, LoginAttempt, User};
use Illuminate\Http\Request;
class SecurityService
{
public function logSecurityEvent(string $event, ?User $user = null, array $data = []): void
{
SecurityLog::create([
'user_id' => $user?->id,
'event' => $event,
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'data' => $data,
'created_at' => now()
]);
}
public function detectSuspiciousActivity(User $user): bool
{
// Multiple login attempts from different IPs
$recentAttempts = LoginAttempt::where('user_id', $user->id)
->where('created_at', '>=', now()->subHour())
->distinct('ip_address')
->count('ip_address');
if ($recentAttempts > 3) {
$this->logSecurityEvent('suspicious_login_pattern', $user, [
'distinct_ips' => $recentAttempts
]);
return true;
}
// Rapid API calls
$apiCalls = SecurityLog::where('user_id', $user->id)
->where('event', 'api_request')
->where('created_at', '>=', now()->subMinute())
->count();
if ($apiCalls > 100) {
$this->logSecurityEvent('api_abuse', $user, [
'requests_per_minute' => $apiCalls
]);
return true;
}
return false;
}
public function blockMaliciousIPs(): void
{
// Find IPs with excessive failed attempts
$maliciousIPs = LoginAttempt::where('successful', false)
->where('created_at', '>=', now()->subDay())
->groupBy('ip_address')
->having(DB::raw('COUNT(*)'), '>', 50)
->pluck('ip_address');
foreach ($maliciousIPs as $ip) {
// Add to blocked IPs list
Cache::put("blocked_ip:{$ip}", true, now()->addHours(24));
$this->logSecurityEvent('ip_blocked', null, ['ip' => $ip]);
}
}
}
Next Steps
Master building robust APIs with Laravel API Development patterns and best practices.
📩 Need help with Laravel security?
Article Category
Authentication & Authorization: Secure Laravel Applications
Master Laravel authentication, authorization systems, API security, role-based access control, and advanced security patterns for enterprise applications.
Consultation & Communication
Direct communication via WhatsApp or phone to understand your project needs precisely.
Planning & Scheduling
Creating clear work plan with specific timeline for each project phase.
Development & Coding
Building projects with latest technologies ensuring high performance and security.
Testing & Delivery
Comprehensive testing and thorough review before final project delivery.