0) { PermissionService::getUserPermissions($userId, true); AuthService::loadTenantDataIntoSession($userId); if (empty($_SESSION['no_active_tenant'])) { UserRepository::updateLastLogin($userId); } } $newToken = bin2hex(random_bytes(32)); $newHash = hash('sha256', $newToken); $newExpires = gmdate('Y-m-d H:i:s', time() + self::lifetimeSeconds()); RememberTokenRepository::updateToken((int) $record['id'], $newHash, $newExpires); self::setCookie($selector, $newToken); return true; } public static function forgetCurrentUser(): void { $value = $_COOKIE[self::cookieName()] ?? ''; if ($value !== '' && strpos($value, ':') !== false) { [$selector] = explode(':', $value, 2); $selector = trim($selector); if ($selector !== '') { $record = RememberTokenRepository::findBySelector($selector); if ($record && isset($record['id'])) { RememberTokenRepository::deleteById((int) $record['id']); } } } self::clearCookie(); } public static function forgetAllForUser(int $userId): void { RememberTokenRepository::deleteByUserId($userId); } public static function expireAllTokensByAdmin(): int { return RememberTokenRepository::expireAllByAdmin(); } private static function setCookie(string $selector, string $token): void { $value = $selector . ':' . $token; $expires = time() + self::lifetimeSeconds(); $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https'); setcookie(self::cookieName(), $value, [ 'expires' => $expires, 'path' => '/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', ]); } private static function clearCookie(): void { $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https'); setcookie(self::cookieName(), '', [ 'expires' => time() - 3600, 'path' => '/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', ]); } private static function lifetimeSeconds(): int { return self::LIFETIME_DAYS * 24 * 60 * 60; } private static function cookieName(): string { $name = getenv('REMEMBER_COOKIE_NAME') ?: self::COOKIE_NAME; return trim($name) !== '' ? $name : self::COOKIE_NAME; } }