This guide covers advanced session security features including session binding, concurrent session management, session rotation, timeouts, and hijacking detection.
Overview
The ArtisanPack Security package provides comprehensive session security through:
- Session Binding: Tie sessions to specific client attributes (IP, user agent, device)
- Concurrent Session Management: Limit simultaneous active sessions
- Session Rotation: Automatically rotate session IDs
- Session Timeouts: Configure idle and absolute timeouts
- Hijacking Detection: Detect and respond to session hijacking attempts
Configuration
Configure session security in config/artisanpack/security.php:
'advanced_sessions' => [
'enabled' => env('SECURITY_ADVANCED_SESSIONS_ENABLED', true),
'binding' => [
'enabled' => true,
'ip_address' => [
'enabled' => true,
'strictness' => 'subnet', // 'none', 'subnet', 'exact'
],
'user_agent' => [
'enabled' => true,
'strictness' => 'exact', // 'none', 'browser_only', 'exact'
],
'bind_to_device' => true, // Requires device fingerprinting
],
'concurrent_sessions' => [
'enabled' => true,
'max_sessions' => 5,
'strategy' => 'oldest', // 'oldest', 'newest'
],
'rotation' => [
'enabled' => true,
'interval_minutes' => 15,
'on_privilege_change' => true,
],
'timeouts' => [
'idle_minutes' => 30,
'idle_warning_minutes' => 25,
'absolute_minutes' => 480, // 8 hours
'extend_on_activity' => true,
],
'hijacking_detection' => [
'enabled' => true,
'action' => 'terminate', // 'terminate', 'require_reauth', 'notify'
],
],
Session Encryption
Enforcing Encrypted Sessions
The package can enforce session encryption in production:
// In config/artisanpack/security.php
'encrypt' => env('SESSION_ENCRYPT', true),
Apply the middleware to routes:
Route::middleware(['auth', 'session.encrypted'])->group(function () {
// These routes require encrypted sessions
});
Checking Session Encryption
php artisan security:check-session
This command verifies:
- Session encryption is enabled
- Session driver is secure (not
filein production) - Cookie settings are secure
Session Binding
Session binding ties a session to specific client attributes, preventing session hijacking by token theft.
IP Address Binding
'ip_address' => [
'enabled' => true,
'strictness' => 'subnet', // Options below
],
Strictness Levels:
| Level | Description | Use Case |
|---|---|---|
none |
No IP binding | Mobile users, VPN users |
subnet |
Same /24 subnet required | Balance of security and usability |
exact |
Exact IP match required | High security environments |
User Agent Binding
'user_agent' => [
'enabled' => true,
'strictness' => 'exact',
],
Strictness Levels:
| Level | Description | Use Case |
|---|---|---|
none |
No UA binding | Maximum compatibility |
browser_only |
Browser name must match | Allows minor version updates |
exact |
Exact UA string required | High security |
Device Binding
When device fingerprinting is enabled, sessions can be bound to specific devices:
'bind_to_device' => true,
This requires the HasDevices trait on your User model and device fingerprint collection during login.
Applying Session Binding
Route::middleware(['auth', 'session.binding'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
Handling Binding Violations
When a binding violation is detected:
use ArtisanPackUI\Security\Events\SessionHijackingAttempted;
Event::listen(SessionHijackingAttempted::class, function ($event) {
Log::warning('Session binding violation', [
'user_id' => $event->userId,
'session_id' => $event->sessionId,
'violation_type' => $event->violationType,
'expected' => $event->expectedValue,
'actual' => $event->actualValue,
]);
});
Concurrent Session Management
Limit the number of simultaneous active sessions per user.
Configuration
'concurrent_sessions' => [
'enabled' => true,
'max_sessions' => 5,
'strategy' => 'oldest',
],
Strategies:
| Strategy | Behavior |
|---|---|
oldest |
Terminate the oldest session when limit reached |
newest |
Prevent new login, keep existing sessions |
User Model Setup
use ArtisanPackUI\Security\Concerns\HasAdvancedSessions;
class User extends Authenticatable
{
use HasAdvancedSessions;
}
Managing Sessions Programmatically
// Get all active sessions for a user
$sessions = $user->activeSessions();
// Get session details
foreach ($sessions as $session) {
echo $session->ip_address;
echo $session->user_agent;
echo $session->last_activity;
echo $session->getLocationDisplay(); // "San Francisco, US"
}
// Terminate a specific session
$user->terminateSession($sessionId);
// Terminate all other sessions (keep current)
$user->terminateOtherSessions();
// Terminate all sessions
$user->terminateAllSessions();
Session Management Commands
# Terminate all sessions for a user
php artisan session:terminate 1
# Terminate sessions by email
php artisan session:terminate user@example.com
# Terminate all sessions except current
php artisan session:terminate 1 --except-current
# Clean up expired sessions
php artisan session:cleanup
Livewire Component
Display and manage sessions in the UI:
<livewire:session-manager />
This component shows:
- Active sessions with device/location info
- Current session indicator
- Ability to terminate individual sessions
- Terminate all other sessions button
Session Rotation
Automatic session ID rotation prevents session fixation attacks.
Configuration
'rotation' => [
'enabled' => true,
'interval_minutes' => 15, // Rotate every 15 minutes
'on_privilege_change' => true, // Rotate after login, role change, etc.
],
Manual Rotation
use ArtisanPackUI\Security\Authentication\Session\SessionSecurityService;
public function sensitiveAction(SessionSecurityService $sessionService)
{
// Rotate session before sensitive action
$sessionService->rotateSession();
// Perform action...
}
Rotation Triggers
Sessions are automatically rotated on:
- Login (always)
- Password change
- Role/permission changes
- Two-factor authentication
- Privilege escalation
- Time-based interval
Session Timeouts
Configure idle and absolute session timeouts.
Configuration
'timeouts' => [
'idle_minutes' => 30, // Expire after 30 min of inactivity
'idle_warning_minutes' => 25, // Warn 5 minutes before expiry
'absolute_minutes' => 480, // Max 8-hour session
'extend_on_activity' => true, // Reset idle timer on activity
],
Idle Timeout Warning
Show a warning before the session expires:
// Listen for the warning event
window.addEventListener('session-expiring', (event) => {
const minutesLeft = event.detail.minutes;
showModal(`Your session expires in ${minutesLeft} minutes. Continue?`);
});
// Extend session on user action
async function extendSession() {
await fetch('/session/extend', { method: 'POST' });
}
Server-side endpoint:
Route::post('/session/extend', function () {
session()->regenerate();
return response()->json(['extended' => true]);
})->middleware('auth');
Absolute Timeout
The absolute timeout ensures sessions don't last indefinitely, even with activity:
// In a middleware or listener
if ($session->created_at->diffInMinutes(now()) > 480) {
Auth::logout();
return redirect('/login')->with('message', 'Session expired. Please log in again.');
}
Hijacking Detection
Detect and respond to potential session hijacking attempts.
Configuration
'hijacking_detection' => [
'enabled' => true,
'action' => 'terminate',
],
Actions:
| Action | Behavior |
|---|---|
terminate |
Immediately terminate the session |
require_reauth |
Require password/2FA verification |
notify |
Log and notify but allow access |
Detection Triggers
The system monitors for:
- IP address changes (based on binding strictness)
- User agent changes
- Device fingerprint changes
- Impossible travel (login from distant location too quickly)
- Concurrent access from multiple IPs
Custom Hijacking Response
use ArtisanPackUI\Security\Events\SessionHijackingAttempted;
Event::listen(SessionHijackingAttempted::class, function ($event) {
// Custom response logic
if ($event->severity === 'critical') {
// Lock the account
$event->user->lockAccount('suspicious_activity');
// Alert security team
Notification::route('slack', config('services.slack.security_channel'))
->notify(new SecurityAlertNotification($event));
}
});
Step-Up Authentication
Require re-authentication for sensitive actions.
Configuration
'step_up_authentication' => [
'enabled' => env('SECURITY_STEP_UP_ENABLED', true),
'timeout_minutes' => 15,
'methods' => [
'password' => true,
'2fa' => true,
'webauthn' => true,
'biometric' => true,
],
'protected_actions' => [
'password_change',
'email_change',
'two_factor_disable',
'delete_account',
],
],
Applying Step-Up Authentication
Route::middleware(['auth', 'step-up'])->group(function () {
Route::post('/account/password', [AccountController::class, 'updatePassword']);
Route::post('/account/email', [AccountController::class, 'updateEmail']);
Route::delete('/account', [AccountController::class, 'destroy']);
});
Programmatic Check
use ArtisanPackUI\Security\Authentication\Session\SessionSecurityService;
public function sensitiveAction(SessionSecurityService $session)
{
if (!$session->hasRecentVerification(15)) {
return redirect()->route('verify.identity')
->with('intended', url()->current());
}
// Proceed with sensitive action
}
Livewire Component
<livewire:step-up-authentication-modal />
Events
The session security system emits these events:
| Event | Trigger |
|---|---|
SessionTerminated |
Session was terminated |
SessionHijackingAttempted |
Potential hijacking detected |
SessionRotated |
Session ID was rotated |
ConcurrentSessionLimitReached |
Max sessions reached |
Best Practices
Production Configuration
// Recommended production settings
'advanced_sessions' => [
'enabled' => true,
'binding' => [
'enabled' => true,
'ip_address' => [
'enabled' => true,
'strictness' => 'subnet', // Balance security/usability
],
'user_agent' => [
'enabled' => true,
'strictness' => 'browser_only', // Allow updates
],
'bind_to_device' => true,
],
'concurrent_sessions' => [
'enabled' => true,
'max_sessions' => 5,
'strategy' => 'oldest',
],
'rotation' => [
'enabled' => true,
'interval_minutes' => 15,
'on_privilege_change' => true,
],
'timeouts' => [
'idle_minutes' => 30,
'idle_warning_minutes' => 25,
'absolute_minutes' => 480,
'extend_on_activity' => true,
],
'hijacking_detection' => [
'enabled' => true,
'action' => 'terminate',
],
],
Session Driver
Use a secure session driver in production:
SESSION_DRIVER=database
# or
SESSION_DRIVER=redis
Avoid file driver in production for:
- Better performance
- Easier session management
- Cross-server compatibility
Secure Cookie Settings
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=lax
SESSION_HTTP_ONLY=true
Troubleshooting
Sessions Expiring Too Quickly
- Check
idle_minutesconfiguration - Verify
extend_on_activityis enabled - Ensure AJAX requests include session cookies
Binding Violations on Mobile
Mobile users may experience IP changes. Consider:
'ip_address' => [
'strictness' => 'none', // Disable for mobile
],
Too Many Session Terminations
If legitimate users are being logged out:
- Increase
concurrent_sessions.max_sessions - Relax binding strictness
- Check for proxy/CDN IP changes
See the Troubleshooting Guide for more solutions.

