User Sessions is a Laravel package for tracking user activity, managing user sessions, and logging detailed session and request data. It is designed to enhance auditing, analytics, and security in your Laravel applications.
Install the package via Composer:
composer require delickate/user-sessionsOr install the latest development version:
composer require delickate/user-sessions:dev-main --prefer-source> php artisan vendor:publish --tag=user-sessions --forceTo uninstall the package:
composer remove delickate/user-sessionsClear Laravel caches after installation/removal:
php artisan cache:clear
php artisan config:clear
composer dump-autoload
php artisan optimize:clearAfter installing, run the migrations to create required database tables:
php artisan migrateAdd the user sessions middleware in your app/Http/Kernel.php under the web middleware group (after authentication middleware):
- \App\Http\Middleware\SecurityHeaders::class inside middleware array
- 'user.sessions' inside middlewareGroups array
protected $middleware = [
//...
//...
\App\Http\Middleware\SecurityHeaders::class, //SANI: user-sessions
\App\Http\Middleware\CheckPasswordExpiry::class, //SANI: user-sessions
];
protected $middlewareGroups = [
'web' => [
//...
//...
//\Illuminate\Auth\Middleware\Authenticate::class,
'user.sessions', //SANI: user-sessions
],
];
protected $routeMiddleware = [
//...
//...
'force.password.change' => \App\Http\Middleware\ForcePasswordChange::class, //SANI: user-sessions
];This middleware automatically logs user activity and stores session information & will provide security protections.
use App\Http\Controllers\UserController;
use App\Http\Controllers\UserSessions\UserSessionController;
use App\Http\Controllers\ChangePasswordController;
use App\Http\Controllers\HomeController;
//SANI: change password
Route::middleware(['auth'])->group(function ()
{
//SANI: user sessions
Route::get('/sessions', [UserSessionController::class, 'index'])
->name('sessions');
Route::get('/user-sessions/{session_id}/activities',
[UserSessionController::class, 'activities']
)->name('user-sessions.activities');
Route::get('/user-sessions/{session_id}/audit-logs',
[UserSessionController::class, 'auditLogs']
)->name('user-sessions.audit-logs');
//SANI: Change password & their rules
Route::get('/change-password', [ChangePasswordController::class, 'show'])
->name('password.change.form');
Route::post('/change-password', [ChangePasswordController::class, 'update'])
->name('password.change.update');
//SANI: Forcefully change password
Route::middleware(['force.password.change'])->group(function ()
{
Route::get('/home', [HomeController::class, 'index']);
});
//SANI: Exception logs
Route::get('/test-exception', function ()
{
throw new Exception("Test Exception Logging");
});
});Open User model and add 'password_changed_at' in fillable like this
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 Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'password_changed_at' //SANI: user-sessions
];Open App\Exceptions\Handler.php file and update it like this
use App\Models\ExceptionLog;
use Throwable;
public function register()
{
$this->reportable(function (Throwable $e) {
try {
ExceptionLog::create([
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
'url' => request()->fullUrl() ?? null,
'method' => request()->method() ?? null,
'ip' => request()->ip() ?? null,
'user_id' => auth()->check() ? auth()->id() : null,
]);
} catch (\Exception $ex) {
// Prevent infinite loop if DB logging fails
}
});
}
//SANI: show 500 error on exception
public function render($request, Throwable $e)
{
if (app()->environment('production'))
{
return response()->view('errors.500', [], 500);
}
return parent::render($request, $e);
}<ul>
<li><a href="{{ url('sessions') }}">Sessions</a></li>
<li><a href="{{ url('/change-password') }}">Change password</a></li>
</ul> Publish all package configuration, views, routes, controllers, and middleware:
php artisan vendor:publish --tag=user-sessions --forceUser Sessions package provides the following features:
- Automatically tracks user sessions.
- Stores session ID, login/logout times, and session metadata.
- Supports multiple simultaneous sessions per user.
- HTTP method (GET, POST, etc.)
- URL and route name
- Payload (excluding sensitive data like passwords)
- IP address and user agent
- Timestamp of the request
- Payload is stored safely as JSON in the database.
- Tracks database changes for configured models.
- Logs UPDATE and DELETE queries automatically.
- Prevents logging of system tables to avoid infinite loops.
- Supports model observers for detailed audit trails.
- Logs every user login and logout event.
- Automatically associates events with user session records.
- user.sessions middleware handles request logging.
- store.user.session middleware stores session IDs for the currently logged-in user.
- Easy to customize or extend.
- Optional UI for viewing user sessions and activity.
- Configurable routes and views.
- Fully publishable for customization.
- Excludes sensitive fields (passwords, tokens) from logs.
- Minimal overhead and fully compatible with Laravel's session system
- Clickjacking Protection (Prevents the application from being embedded in iframe elements on external domains)
- MIME-Type Sniffing Prevention (Prevents browsers from interpreting files as a different MIME type than declared)
- Cross-Site Scripting (XSS) Protection (Legacy Browsers)
- Referrer Policy Enforcement (Controls how much referrer information is shared during navigation)
- Content Security Policy (Restricts the sources from which the browser may load resources)
- HTTP Strict Transport Security (Forces browsers to use HTTPS for all future requests)
- Strong password complexity enforcement
- Password history restriction (reuse prevention)
- Forced password change mechanisms
- 90-day password expiration enforcement
- Secure password storage using strong hashing
- Administrative forced reset capability
This version includes:
- Installation & uninstall instructions
- Middleware setup
- Publishing files
- Detailed feature list
- Configuration & usage examples
- Troubleshooting
- License & contributing info
Here is list of commands in order to run
> php artisan session:table (only if session is being store into database. its optional)
> composer require delickate/user-sessions
> php artisan vendor:publish --tag=user-sessions --force
> php artisan migrateTo remove package run following commands
> composer remove delickate/user-sessions
> composer clear-cache