Sessions and Audit Log
Two related admin pages: the live list of who is signed in right now, and the historical log of every security-relevant thing that has happened.
The Sessions page at /sessions shows which operators are currently signed in, from where, and how. From here an administrator can end any session immediately. The Audit Log page at /audit-log (titled “User Activity” in the sidebar) shows the full trail of authentication events, user-management actions, security-state changes, and resource modifications.
Both pages are administrator-only. For background on how sessions and tokens work see Authentication (chapter 29). For the user records themselves see User Management (chapter 27).
Active Sessions Page
Section titled “Active Sessions Page”A live table of every session currently signed in, refreshed every 30 seconds.
The page header carries the title, a session count (“12 active sessions”), and a refresh button. Below that are filters; below those is the per-user summary; and at the bottom is the full session table.
Filters
Section titled “Filters”A row of two controls:
| Control | Effect |
|---|---|
| Search | Free-text filter that matches against the username and the IP address. As you type, the list narrows. |
| Auth Method | Drop-down: All Methods, Local, Local + MFA, Google OAuth, Keycloak, API Key. |
Both filters apply together (AND). The session count in the header reflects the filtered total.
Sessions by User
Section titled “Sessions by User”A scrollable panel showing one row per distinct username, with the count of their active sessions and a circular avatar icon. If a user has more than one active session, an End All button appears on their row.
+-------------------------------------------------+| Sessions by User |+-------------------------------------------------+| [JS] john.smith 3 active sessions || [End All] |+-------------------------------------------------+| [AC] alice.chen 1 active session |+-------------------------------------------------+Clicking End All opens a confirmation modal. On confirm, every active session belonging to that user is marked inactive — they are signed out everywhere within seconds.
All Sessions Table
Section titled “All Sessions Table”The main table lists every active session with pagination at top and bottom (25 / 50 / 100 / 250 per page).
| Column | What it shows |
|---|---|
| User | Username with a person icon. |
| IP Address | The source IP recorded when the session was created. |
| Auth Method | A coloured pill: blue for local, green-with-shield for local+MFA, red for Google, orange for Keycloak, yellow for API key. |
| Last Activity | Relative time of the most recent request from this session (“3 minutes ago”, “just now”). |
| Created | Relative time when the session began. |
| Expires | Relative time until the session token expires. Red with a warning icon if past expiry. |
| Actions | A red logout icon on the far right. |
Every row’s action icon opens a confirmation modal that ends just that one session.
Ending a Session
Section titled “Ending a Session”Click the logout icon on a row. The modal warns:
Are you sure you want to terminate this session for “<username>”? They will be logged out immediately.
On confirm, the session row is marked inactive. The next API call from that browser fails with 401 and the user is bounced to the login page with a “Your session was terminated by an administrator” message.
Ending a session is recorded in the audit log as a Session Terminated event with the operator who did it, the IP, and the target session ID.
Tip: when you suspect an account has been compromised, the fastest containment is: deactivate the account in User Management, then End All sessions for that user here. The deactivation closes the door; the session purge throws everyone out who was already inside.
Behaviour Notes
Section titled “Behaviour Notes”- The page auto-refreshes every 30 seconds; you can force a refresh with the refresh button.
- Expired sessions are not shown by default — only sessions that are still active and within their expiry window appear.
- The “Auth Method” pill carries semantic meaning:
local+mfais a stronger assurance thanlocal; an MFA-enabled user who signed in without MFA could not have arrived atlocal+mfa.
User Activity (Audit Log) Page
Section titled “User Activity (Audit Log) Page”A searchable, filterable, paginated table of every security-relevant event the appliance has recorded.
The page header is “User Activity” and carries:
- A time-range picker with previous / next arrows and a drop-down (Last 24 hours, Last 7 days, Last 30 days, custom).
- A refresh button.
- A CSV export button.
Below the header are four stat cards: Total Events, Successful, Failed, and Unique Users — each scoped to the current filter and time range. The numbers update as you change filters.
The Filter Panel
Section titled “The Filter Panel”Click Filters to open a panel with four controls:
| Filter | Behaviour |
|---|---|
| Search | Free text over username, target username, IP, and event type. |
| Event Type | Drop-down listing every recorded event type (see the table below) plus “All Events”. |
| Status | All / Success / Failed. |
| Clear All | Resets all three filters. |
The Filters button itself shows an “Active” badge when any filter is set.
Event Categories
Section titled “Event Categories”The audit log groups events into six categories, each with its own icon set:
| Category | Examples |
|---|---|
| Authentication | Login, Logout, Login Failed, Token Refresh, MFA Challenge, MFA Verified, MFA Failed |
| Account Security | Password Changed, Password Reset, Account Locked, Account Unlocked, MFA Enabled, MFA Disabled |
| User Management | User Created, User Modified, User Deactivated, User Reactivated |
| Session Management | Session Created, Session Terminated, Session Expired |
| API Keys | API Key Created, API Key Revoked, API Key Used |
| OAuth | OAuth Linked, OAuth Unlinked, OAuth Login |
Beyond those, the same table also stores events for resource changes outside the auth subsystem — device actions, bulk actions, firewall configuration changes, automation rule edits, notification rule edits, DHCP filter changes, report changes, and other administrative operations. These all share the same table and the same filter mechanics; the event-type drop-down lists the auth-focused subset, but search will find any of them.
The Event Table
Section titled “The Event Table”Each row represents one event. The table has these columns:
| Column | What it shows |
|---|---|
| ▸ | Expand chevron, shown if the row has additional details. |
| Timestamp | Local date and time to the second. |
| Event | Icon plus human-readable label (“Login Failed”, “Account Unlocked”, etc.). |
| User | The operator who performed the action. “Anonymous” for events that occurred before authentication (e.g. failed logins with unknown username). |
| Target | If the action affected another user (e.g. “Admin reset password for alice.chen”), the target username appears here. |
| IP Address | The source IP. |
| Status | Green check for success, red X for failure. |
Pagination appears at top and bottom (25 / 50 / 100 / 250 per page).
Expanded Details
Section titled “Expanded Details”Click a row to expand it. If the event carries additional context, the panel below shows a JSON block with the raw details — for example, for a Login Failed event you might see the failure reason, the user-agent string, and any extra context the audit subsystem attached.
Details:{ "reason": "invalid_password", "failed_attempt": 3}
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...Use the expanded view to distinguish, for instance, a failed login because of a wrong password versus one because of an IP restriction. Both show as “Login Failed” in the row, but the reason in the details panel tells them apart.
CSV Export
Section titled “CSV Export”Click CSV in the header to export every event currently matching the filter and time range. The download is a flat CSV — one row per event, one column per field. Use this for compliance archives, external SIEM ingestion, or simply for grepping at scale.
The CSV is named audit-log-YYYY-MM-DD.csv. The current time-range, search, and event-type filters are all applied to the export.
Auto-refresh
Section titled “Auto-refresh”The audit log refreshes every 60 seconds while the page is open. The latest events appear at the top of the table.
Retention
Section titled “Retention”Audit log rows are kept on the appliance for as long as the database retention policy allows.
By default the appliance stores audit events indefinitely — they are small rows in ClickHouse. There is no automatic purge of audit records out of the box. If you need a hard retention window (e.g. 90 days for compliance), set a TTL on the audit log table during installation or via a migration. Once set, ClickHouse will remove expired rows during background merges.
For external long-term retention, the recommended pattern is to export to CSV on a regular schedule and feed the export into your central log store.
Reading the Audit Log Effectively
Section titled “Reading the Audit Log Effectively”A few common investigation patterns.
Who locked an account?
Section titled “Who locked an account?”Filter by Event Type = Account Locked. The User column shows the username being locked. Expand the row to see the trailing failed-attempt count and IP. Cross-reference with the surrounding Login Failed events from the same IP to see the attack pattern.
Who changed a firewall rule?
Section titled “Who changed a firewall rule?”Filter by Search = nft_config. Every firewall configuration event will appear with the operator name and timestamp. Expand for details on what changed.
Was anyone signed in at <some past time>?
Section titled “Was anyone signed in at <some past time>?”Set the time range to the window in question and filter by Event Type = Login. Every successful sign-in during that window appears; combine with Logout and Session Expired events to reconstruct who was actively on the appliance.
Did an admin run anything destructive?
Section titled “Did an admin run anything destructive?”Filter by Status = Success and Search = delete or revoke or terminate. You will see every user deletion, API key revocation, session termination, capture deletion, etc. — usually a small enough list to scan by eye.
What happened to user X?
Section titled “What happened to user X?”Filter by Search = <username>. Every event that names them as actor or as target appears, sorted newest-first. Useful for understanding why a user is locked out, why their permissions changed, or what they have been doing.
Permissions and Access Control
Section titled “Permissions and Access Control”Both pages require admin role.
- The Sessions page is hidden from operators and viewers; if a non-admin attempts to navigate to
/sessionsthey are redirected. - The Audit Log page is similarly admin-only. Operators and viewers cannot see the page, and the underlying API rejects their requests with 403.
- The CSV export honours the same role check; an operator cannot download audit data through any of the GUI paths.
If you need a non-admin user to be able to view audit data, the only supported path is to grant them admin role temporarily, or to export the CSV and share it through your normal data-handling channels.
Cross-references
Section titled “Cross-references”Where else in the GUI these events surface.
- The login page redirect after a forced session termination uses a
logout_reasonvalue carried in the browser session storage. The reason is rendered as an error banner the next time the user visits/login. See Authentication (chapter 29). - The Sessions by User panel uses the same
max_concurrentsetting that the login flow respects. Lowering the limit will end old sessions on a user’s next sign-in, not retroactively. - Device-action audit rows are also visible on the Actions (chapter 15) page, where each row points back to the action that produced it.
When Sessions Don’t Show Up
Section titled “When Sessions Don’t Show Up”A short list of situations where you might expect to see an entry but won’t.
- Anonymous API calls never appear in the sessions list because they never produced a session row. They do appear in the audit log as
Login Failedevents. - Expired sessions drop out of the sessions list as soon as they expire. The history of the session is still in the audit log under
Session Createdand eitherSession TerminatedorSession Expired. - OAuth callbacks that never completed (the user got redirected to Google but never came back) leave no session row, only a single audit row representing the original OAuth initiation.
- API key-based requests are tracked under a separate auth method; they may show in the sessions list as
api_keywhen long-lived, or as nothing when the API key was used statelessly. The audit log captures every API key use underAPI Key Used.
Troubleshooting
Section titled “Troubleshooting”The Sessions page shows my own session as expired. Your token is still valid but the session record’s
expires_athas passed. The next request you make should trigger a forced sign-out. Refresh the GUI; if you stay signed in, the row has already been refreshed and the timestamp display is just slightly stale (the page polls every 30 seconds).
End All ended my session too. If you ended all sessions for your own user (perhaps as a precaution), you ended yours along with everyone else’s. Re-sign in.
Audit log shows no events. Check the time range — it defaults to the last 24 hours. Stretch it to “Last 30 days” or set a custom range to verify whether the database has any rows at all. If nothing appears at any range, the audit logger may not be initialised — check the appliance log for an
auditLoggerwarning at startup.
CSV export is empty. Either the current filter matches nothing, or the time range contains no events. The CSV applies all current filters; widen them and retry.
Audit Event Reference
Section titled “Audit Event Reference”A reference appendix for administrators: the canonical list of event types, the JSON shape of each event’s details field, ready-to-run ClickHouse queries, and the audit-log API.
Event Types by Category
Section titled “Event Types by Category”Every event written to the audit log carries an event_type string. The values below are the complete set, grouped by what they describe.
Authentication
Section titled “Authentication”| Event Type | Description | Logged When |
|---|---|---|
login | Successful authentication | User logs in via UI or API |
login_failed | Failed authentication attempt | Invalid credentials, locked account |
logout | User logout | Explicit logout or session termination |
token_refresh | JWT token refreshed | Token renewal via refresh endpoint |
mfa_challenge | MFA challenge initiated | User prompted for 2FA code |
mfa_verified | MFA verification successful | Correct 2FA code entered |
mfa_failed | MFA verification failed | Incorrect 2FA code |
Account Security
Section titled “Account Security”| Event Type | Description | Logged When |
|---|---|---|
password_change | Password changed | User or admin changes password |
password_reset | Password reset initiated | Reset link sent or password force-changed |
account_locked | Account locked | Too many failed login attempts |
account_unlocked | Account unlocked | Admin unlocks user account |
mfa_enabled | MFA enabled | User or admin enables 2FA |
mfa_disabled | MFA disabled | User or admin disables 2FA |
User Management
Section titled “User Management”| Event Type | Description | Logged When |
|---|---|---|
user_created | New user account created | Admin creates user |
user_modified | User account modified | Role, permissions, email, or status changed |
user_deleted | User account deleted | Admin deletes user |
user_reactivated | User account reactivated | Disabled user re-enabled |
Session Management
Section titled “Session Management”| Event Type | Description | Logged When |
|---|---|---|
session_created | New session started | Login creates new session |
session_terminated | Session terminated | Admin or user terminates session |
session_expired | Session expired | Future-reserved; defined but not currently emitted. |
API Keys
Section titled “API Keys”| Event Type | Description | Logged When |
|---|---|---|
api_key_created | API key generated | User creates new API key |
api_key_revoked | API key revoked | User or admin revokes API key |
api_key_used | API key authentication | Future-reserved; defined but not currently emitted. |
Device Actions
Section titled “Device Actions”| Event Type | Description | Logged When |
|---|---|---|
device_action | Action executed on MAC | Block, unblock, throttle, allow, deny, monitor |
bulk_action_execute | Bulk action job created | Bulk action started on multiple MACs |
bulk_action_cancel | Bulk action cancelled | Scheduled or running bulk action cancelled |
Firewall Management
Section titled “Firewall Management”| Event Type | Description | Logged When |
|---|---|---|
nft_config_created | NFTables config created | New firewall configuration saved |
nft_config_updated | NFTables config updated | Existing configuration modified |
nft_config_deleted | NFTables config deleted | Configuration removed |
nft_config_applied | NFTables config applied | Configuration activated on the system |
Automation Rules
Section titled “Automation Rules”| Event Type | Description | Logged When |
|---|---|---|
automation_rule_created | Automation rule created | New detection rule added |
automation_rule_updated | Automation rule updated | Rule configuration modified |
automation_rule_deleted | Automation rule deleted | Rule removed |
automation_rule_enabled | Automation rule enabled | Rule activated |
automation_rule_disabled | Automation rule disabled | Rule deactivated |
DHCP Filters
Section titled “DHCP Filters”| Event Type | Description | Logged When |
|---|---|---|
dhcp_filter_created | DHCP stream filter created | User creates saved filter |
dhcp_filter_updated | DHCP stream filter updated | Filter criteria modified |
dhcp_filter_deleted | DHCP stream filter deleted | Saved filter removed |
Dashboards
Section titled “Dashboards”| Event Type | Description | Logged When |
|---|---|---|
dashboard_updated | Dashboard configuration saved | User modifies dashboard layout |
Configuration
Section titled “Configuration”| Event Type | Description | Logged When |
|---|---|---|
config_changed | System configuration changed | Operational settings modified |
ip_restriction_added | IP restriction added | New IP access rule created |
ip_restriction_removed | IP restriction removed | IP access rule deleted |
retention_changed | Data retention policy changed | TTL settings modified |
Details Field Schema
Section titled “Details Field Schema”Each event carries a details JSON object whose shape depends on the event type. The tables below enumerate the fields written for each event family.
Device Actions
Section titled “Device Actions”| Field | Type | Description |
|---|---|---|
mac | string | Target MAC address |
action_type | string | block, unblock, throttle, allow, deny, monitor |
duration | int | Duration in seconds (0 = permanent) |
reason | string | Reason for the action |
comment | string | Optional operator comment |
Bulk Actions
Section titled “Bulk Actions”| Field | Type | Description |
|---|---|---|
job_id | string | UUID of the bulk action job |
action_type | string | Action to apply |
duration | int | Duration in seconds |
reason | string | Reason for bulk action |
estimated_macs | int | Number of MACs affected |
criteria_hash | string | Hash of selection criteria |
scheduled_at | string | ISO 8601 timestamp if scheduled |
Firewall Configurations
Section titled “Firewall Configurations”| Field | Type | Description |
|---|---|---|
config_id | string | UUID of the configuration |
config_name | string | Human-readable name |
mode | string | Apply mode: add, table, all |
comment | string | Configuration description |
Automation Rules
Section titled “Automation Rules”| Field | Type | Description |
|---|---|---|
rule_id | string | UUID of the rule |
rule_name | string | Rule name |
action_type | string | analyze, block, throttle, etc. |
priority | int | Rule priority (1-100) |
Prompts
Section titled “Prompts”| Field | Type | Description |
|---|---|---|
prompt_id | string | UUID of the prompt |
prompt_name | string | Prompt name |
is_default | bool | Whether set as default |
DHCP Filters
Section titled “DHCP Filters”| Field | Type | Description |
|---|---|---|
filter_id | string | UUID of the filter |
filter_name | string | Filter name |
Dashboards
Section titled “Dashboards”| Field | Type | Description |
|---|---|---|
dashboard_count | int | Number of dashboards saved |
User Management
Section titled “User Management”| Field | Type | Description |
|---|---|---|
role | string | User role |
permissions | array | List of permissions |
self_change | bool | Whether user changed own settings |
Login Events
Section titled “Login Events”| Field | Type | Description |
|---|---|---|
auth_method | string | local, oauth, api_key |
reason | string | Failure reason (for failed logins) |
failed_attempts | int | Count before lockout |
Querying the Audit Log
Section titled “Querying the Audit Log”SSH into the appliance and run these against ClickHouse with clickhouse-client. The table name is users_audit_log in the configured database (typically DHCP_DPI_01).
Basic queries
Section titled “Basic queries”-- Recent audit events (last 24 hours)SELECT *FROM users_audit_logWHERE timestamp >= now() - INTERVAL 24 HOURORDER BY timestamp DESCLIMIT 100
-- All device actions by a specific userSELECT *FROM users_audit_logWHERE event_type = 'device_action' AND username = 'operator1'ORDER BY timestamp DESC
-- Failed login attempts from external IPsSELECT timestamp, username, ip_address, JSONExtractString(details, 'reason') as reasonFROM users_audit_logWHERE event_type = 'login_failed' AND NOT startsWith(ip_address, '192.168.') AND NOT startsWith(ip_address, '10.')ORDER BY timestamp DESCLIMIT 50
-- All firewall changes in the last weekSELECT timestamp, username, event_type, ip_address, detailsFROM users_audit_logWHERE event_type LIKE 'nft_config%' AND timestamp >= now() - INTERVAL 7 DAYORDER BY timestamp DESCSecurity investigation
Section titled “Security investigation”-- User activity timelineSELECT timestamp, event_type, JSONExtractString(details, 'mac') as mac, JSONExtractString(details, 'action_type') as actionFROM users_audit_logWHERE username = 'suspect_user' AND timestamp BETWEEN '2026-01-15 00:00:00' AND '2026-01-17 23:59:59'ORDER BY timestamp
-- All admin actions on a specific dateSELECT *FROM users_audit_logWHERE toDate(timestamp) = '2026-01-17' AND event_type IN ('user_created', 'user_modified', 'user_deleted', 'config_changed', 'nft_config_applied')ORDER BY timestamp
-- Actions from unusual IP addressesSELECT ip_address, count() as action_count, groupArray(DISTINCT event_type) as event_typesFROM users_audit_logWHERE timestamp >= now() - INTERVAL 7 DAY AND ip_address NOT IN ('192.168.1.100', '192.168.1.50', '10.0.0.15')GROUP BY ip_addressHAVING action_count > 10ORDER BY action_count DESC
-- Bulk action history with affected MAC countsSELECT timestamp, username, JSONExtractString(details, 'job_id') as job_id, JSONExtractString(details, 'action_type') as action_type, JSONExtractInt(details, 'estimated_macs') as mac_countFROM users_audit_logWHERE event_type = 'bulk_action_execute'ORDER BY timestamp DESCLIMIT 20Compliance reporting
Section titled “Compliance reporting”-- Daily action summary by userSELECT toDate(timestamp) as date, username, event_type, count() as action_countFROM users_audit_logWHERE timestamp >= now() - INTERVAL 30 DAYGROUP BY date, username, event_typeORDER BY date DESC, username, action_count DESC
-- User management audit trailSELECT timestamp, username as admin_user, event_type, target_username, detailsFROM users_audit_logWHERE event_type IN ('user_created', 'user_modified', 'user_deleted', 'account_locked', 'account_unlocked', 'mfa_enabled', 'mfa_disabled')ORDER BY timestamp DESCLIMIT 100
-- Configuration change historySELECT timestamp, username, event_type, ip_address, detailsFROM users_audit_logWHERE event_type IN ('config_changed', 'retention_changed', 'ip_restriction_added', 'ip_restriction_removed')ORDER BY timestamp DESCTip: always include a time-range filter and a
LIMITfor interactive queries. The audit log table is indexed onevent_type,user_id, andsuccess— filter on those columns whenever possible.
API Access
Section titled “API Access”The audit log is also reachable over HTTPS for programmatic export or integration with an external SIEM.
GET /api/audit/logs| Parameter | Type | Description |
|---|---|---|
start_time | ISO 8601 | Start of time range. Optional; defaults to the last 7 days. |
end_time | ISO 8601 | End of time range. Optional. |
event_type | string | Filter by exact event-type string. |
search | string | Free-text search across event details. |
success | bool | Filter by success/failure outcome. |
limit | int | Max results (default 100). |
offset | int | Pagination offset. |
Filtering by username or user_id is not exposed on this endpoint. To list events for a single user, use search=<username> against the free-text field.
Example request:
curl -s -k -H "Authorization: Bearer $TOKEN" \ "https://192.168.1.245/api/audit/logs?event_type=device_action&limit=50"Note: the API route is gated by the
audit.viewpermission, which by default ships with the admin and operator role sets. The Sessions and Audit Log GUI pages themselves remain admin-only.