imransaleem / security-suite
Laravel security package: audit logs, password policy, idle timeout, login block, HTTP request logging.
Package info
github.com/imransaleem25/security-suite
Language:Blade
pkg:composer/imransaleem/security-suite
Requires
- php: ^8.0
- illuminate/database: ^8.0|^9.0|^10.0
- illuminate/http: ^8.0|^9.0|^10.0
- illuminate/routing: ^8.0|^9.0|^10.0
- illuminate/support: ^8.0|^9.0|^10.0
- illuminate/validation: ^8.0|^9.0|^10.0
Suggests
- spatie/laravel-permission: Required for admin UI routes that use the role middleware (^5.0)
This package is not auto-updated.
Last update: 2026-06-05 04:09:55 UTC
README
A plug-and-play Laravel package for audit logging, password policy, login lockout, idle session timeout, password history UI, and optional HTTP request logging.
Features
| Feature | Description |
|---|---|
| Audit Logs | Track create/update/delete actions with before/after diff |
| Password Policy | Complexity rules, expiry, history (prevent reuse of last N passwords) |
| Login Block | Auto-block after N failed attempts — temporary lock or admin unblock |
| Idle Timeout | End session after inactivity (server middleware + optional client ping) |
| Password History UI | Admin views for per-user and global password change history |
| HTTP Logger | Optional request/response logging with admin viewer |
Requirements
- PHP 8.0+
- Laravel 8, 9, or 10
- spatie/laravel-permission suggested for admin UI routes (
rolemiddleware)
Installation
From GitHub (before Packagist)
"repositories": [ { "type": "vcs", "url": "https://github.com/imransaleem/security-suite" } ], "require": { "imransaleem/security-suite": "dev-main" }
composer require imransaleem/security-suite:dev-main
From Packagist (after submission)
composer require imransaleem/security-suite
Publish & migrate
php artisan vendor:publish --tag=security-suite-config
php artisan vendor:publish --tag=security-suite-migrations
php artisan vendor:publish --tag=security-suite-views # optional
php artisan migrate
Middleware (app/Http/Kernel.php)
protected $middlewareGroups = [ 'web' => [ // ... \ImranSaleem\SecuritySuite\Middleware\CheckPasswordExpiry::class, \ImranSaleem\SecuritySuite\Middleware\CheckIdleTimeout::class, // optional: // \ImranSaleem\SecuritySuite\Middleware\LogHttpRequest::class, ], ];
User model
Add to $fillable and $casts:
'login_attempts', 'locked_until', 'is_blocked', 'password_changed_at', 'forced_change_password',
'locked_until' => 'datetime', 'is_blocked' => 'boolean', 'forced_change_password' => 'boolean',
Host app layout
Admin views use config('security_suite.layout') (default layouts.app). The password-expired screen uses security_suite.password_expired_layout (default layouts.guest).
Routes
All package routes are prefixed (default /security):
| Route name | Path |
|---|---|
idle.ping |
GET /security/idle-ping |
idle.config |
GET /security/idle-config |
password.expired |
GET /security/password-expired |
audit.logs.index |
GET /security/audit-logs |
http.logs.index |
GET /security/http-logs |
Change the prefix with SECURITY_SUITE_ROUTE_PREFIX in .env.
Configuration
.env
SECURITY_SUITE_ROUTE_PREFIX=security SECURITY_SUITE_LAYOUT=layouts.app SECURITY_SUITE_PASSWORD_EXPIRED_LAYOUT=layouts.guest SECURITY_SUITE_HOME_ROUTE=dashboard SECURITY_SUITE_LOGIN_ROUTE=login SECURITY_SUITE_IDLE_TIMEOUT=15 LOGIN_BLOCK_MODE=temporary LOGIN_MAX_ATTEMPTS=5 LOGIN_LOCKOUT_MINUTES=15 PASSWORD_MIN_LENGTH=12 PASSWORD_EXPIRY_DAYS=30 PASSWORD_HISTORY_COUNT=2 AUDIT_VIEWER_ROLE=admin HTTP_LOGGER_ENABLED=true
Custom modules & actions
Publish config/audit.php and set:
modules— filter dropdown list; leave[]to load modules from the databaseactions— allowed query filters; leave[]to allow any action
Idle timeout (client-side)
@auth <script> (function () { fetch('{{ route("idle.config") }}') .then(r => r.json()) .then(cfg => { const TIMEOUT_MS = cfg.timeout_ms; const WARN_BEFORE = cfg.warn_before; let idleTimer, warnTimer; function reset() { clearTimeout(idleTimer); clearTimeout(warnTimer); fetch('{{ route("idle.ping") }}', { credentials: 'same-origin' }); warnTimer = setTimeout(() => alert('Session expiring soon!'), TIMEOUT_MS - WARN_BEFORE); idleTimer = setTimeout(() => { const form = document.getElementById('logout-form'); if (form) form.submit(); }, TIMEOUT_MS); } ['mousemove','keydown','click','scroll'].forEach(e => document.addEventListener(e, reset, { passive: true })); reset(); }); })(); </script> @endauth
Background polling (idle)
Add host route names to config/security_suite.php → idle_no_refresh_route_names so polling does not reset the idle timer.
Usage
Audit logging
use ImranSaleem\SecuritySuite\Models\AuditLog; AuditLog::write('users', 'created', $user, [], $user->only(['name', 'email'])); AuditLog::write('orders', 'updated', $order, ['status' => 'pending'], ['status' => 'shipped']);
Login block
use ImranSaleem\SecuritySuite\Services\LoginBlockService; if ($user && $error = $this->blocker->checkBlock($user)) { return back()->withErrors(['email' => $error]); }
Password policy
use ImranSaleem\SecuritySuite\Services\PasswordPolicyService; $request->validate(['new_password' => ['required', 'confirmed', $this->policy->complexityRule()]]); if ($this->policy->isReused($user, $request->new_password)) { /* ... */ }
Package structure
security-suite/
├── config/
│ ├── security_suite.php
│ ├── audit.php
│ ├── login_security.php
│ ├── password_policy.php
│ └── http_logger.php
├── database/migrations/
├── routes/security.php
├── resources/views/
└── src/
License
MIT