Skip to content

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).


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.

A row of two controls:

ControlEffect
SearchFree-text filter that matches against the username and the IP address. As you type, the list narrows.
Auth MethodDrop-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.

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.

The main table lists every active session with pagination at top and bottom (25 / 50 / 100 / 250 per page).

ColumnWhat it shows
UserUsername with a person icon.
IP AddressThe source IP recorded when the session was created.
Auth MethodA coloured pill: blue for local, green-with-shield for local+MFA, red for Google, orange for Keycloak, yellow for API key.
Last ActivityRelative time of the most recent request from this session (“3 minutes ago”, “just now”).
CreatedRelative time when the session began.
ExpiresRelative time until the session token expires. Red with a warning icon if past expiry.
ActionsA red logout icon on the far right.

Every row’s action icon opens a confirmation modal that ends just that one 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.

  • 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+mfa is a stronger assurance than local; an MFA-enabled user who signed in without MFA could not have arrived at local+mfa.

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.

Click Filters to open a panel with four controls:

FilterBehaviour
SearchFree text over username, target username, IP, and event type.
Event TypeDrop-down listing every recorded event type (see the table below) plus “All Events”.
StatusAll / Success / Failed.
Clear AllResets all three filters.

The Filters button itself shows an “Active” badge when any filter is set.

The audit log groups events into six categories, each with its own icon set:

CategoryExamples
AuthenticationLogin, Logout, Login Failed, Token Refresh, MFA Challenge, MFA Verified, MFA Failed
Account SecurityPassword Changed, Password Reset, Account Locked, Account Unlocked, MFA Enabled, MFA Disabled
User ManagementUser Created, User Modified, User Deactivated, User Reactivated
Session ManagementSession Created, Session Terminated, Session Expired
API KeysAPI Key Created, API Key Revoked, API Key Used
OAuthOAuth 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.

Each row represents one event. The table has these columns:

ColumnWhat it shows
Expand chevron, shown if the row has additional details.
TimestampLocal date and time to the second.
EventIcon plus human-readable label (“Login Failed”, “Account Unlocked”, etc.).
UserThe operator who performed the action. “Anonymous” for events that occurred before authentication (e.g. failed logins with unknown username).
TargetIf the action affected another user (e.g. “Admin reset password for alice.chen”), the target username appears here.
IP AddressThe source IP.
StatusGreen check for success, red X for failure.

Pagination appears at top and bottom (25 / 50 / 100 / 250 per page).

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.

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.

The audit log refreshes every 60 seconds while the page is open. The latest events appear at the top of the table.


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.


A few common investigation patterns.

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.

Filter by Search = nft_config. Every firewall configuration event will appear with the operator name and timestamp. Expand for details on what changed.

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.

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.

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.


Both pages require admin role.

  • The Sessions page is hidden from operators and viewers; if a non-admin attempts to navigate to /sessions they 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.


Where else in the GUI these events surface.

  • The login page redirect after a forced session termination uses a logout_reason value 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_concurrent setting 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.

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 Failed events.
  • 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 Created and either Session Terminated or Session 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_key when long-lived, or as nothing when the API key was used statelessly. The audit log captures every API key use under API Key Used.

The Sessions page shows my own session as expired. Your token is still valid but the session record’s expires_at has 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 auditLogger warning 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.


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.

Every event written to the audit log carries an event_type string. The values below are the complete set, grouped by what they describe.

Event TypeDescriptionLogged When
loginSuccessful authenticationUser logs in via UI or API
login_failedFailed authentication attemptInvalid credentials, locked account
logoutUser logoutExplicit logout or session termination
token_refreshJWT token refreshedToken renewal via refresh endpoint
mfa_challengeMFA challenge initiatedUser prompted for 2FA code
mfa_verifiedMFA verification successfulCorrect 2FA code entered
mfa_failedMFA verification failedIncorrect 2FA code
Event TypeDescriptionLogged When
password_changePassword changedUser or admin changes password
password_resetPassword reset initiatedReset link sent or password force-changed
account_lockedAccount lockedToo many failed login attempts
account_unlockedAccount unlockedAdmin unlocks user account
mfa_enabledMFA enabledUser or admin enables 2FA
mfa_disabledMFA disabledUser or admin disables 2FA
Event TypeDescriptionLogged When
user_createdNew user account createdAdmin creates user
user_modifiedUser account modifiedRole, permissions, email, or status changed
user_deletedUser account deletedAdmin deletes user
user_reactivatedUser account reactivatedDisabled user re-enabled
Event TypeDescriptionLogged When
session_createdNew session startedLogin creates new session
session_terminatedSession terminatedAdmin or user terminates session
session_expiredSession expiredFuture-reserved; defined but not currently emitted.
Event TypeDescriptionLogged When
api_key_createdAPI key generatedUser creates new API key
api_key_revokedAPI key revokedUser or admin revokes API key
api_key_usedAPI key authenticationFuture-reserved; defined but not currently emitted.
Event TypeDescriptionLogged When
device_actionAction executed on MACBlock, unblock, throttle, allow, deny, monitor
bulk_action_executeBulk action job createdBulk action started on multiple MACs
bulk_action_cancelBulk action cancelledScheduled or running bulk action cancelled
Event TypeDescriptionLogged When
nft_config_createdNFTables config createdNew firewall configuration saved
nft_config_updatedNFTables config updatedExisting configuration modified
nft_config_deletedNFTables config deletedConfiguration removed
nft_config_appliedNFTables config appliedConfiguration activated on the system
Event TypeDescriptionLogged When
automation_rule_createdAutomation rule createdNew detection rule added
automation_rule_updatedAutomation rule updatedRule configuration modified
automation_rule_deletedAutomation rule deletedRule removed
automation_rule_enabledAutomation rule enabledRule activated
automation_rule_disabledAutomation rule disabledRule deactivated
Event TypeDescriptionLogged When
dhcp_filter_createdDHCP stream filter createdUser creates saved filter
dhcp_filter_updatedDHCP stream filter updatedFilter criteria modified
dhcp_filter_deletedDHCP stream filter deletedSaved filter removed
Event TypeDescriptionLogged When
dashboard_updatedDashboard configuration savedUser modifies dashboard layout
Event TypeDescriptionLogged When
config_changedSystem configuration changedOperational settings modified
ip_restriction_addedIP restriction addedNew IP access rule created
ip_restriction_removedIP restriction removedIP access rule deleted
retention_changedData retention policy changedTTL settings modified

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.

FieldTypeDescription
macstringTarget MAC address
action_typestringblock, unblock, throttle, allow, deny, monitor
durationintDuration in seconds (0 = permanent)
reasonstringReason for the action
commentstringOptional operator comment
FieldTypeDescription
job_idstringUUID of the bulk action job
action_typestringAction to apply
durationintDuration in seconds
reasonstringReason for bulk action
estimated_macsintNumber of MACs affected
criteria_hashstringHash of selection criteria
scheduled_atstringISO 8601 timestamp if scheduled
FieldTypeDescription
config_idstringUUID of the configuration
config_namestringHuman-readable name
modestringApply mode: add, table, all
commentstringConfiguration description
FieldTypeDescription
rule_idstringUUID of the rule
rule_namestringRule name
action_typestringanalyze, block, throttle, etc.
priorityintRule priority (1-100)
FieldTypeDescription
prompt_idstringUUID of the prompt
prompt_namestringPrompt name
is_defaultboolWhether set as default
FieldTypeDescription
filter_idstringUUID of the filter
filter_namestringFilter name
FieldTypeDescription
dashboard_countintNumber of dashboards saved
FieldTypeDescription
rolestringUser role
permissionsarrayList of permissions
self_changeboolWhether user changed own settings
FieldTypeDescription
auth_methodstringlocal, oauth, api_key
reasonstringFailure reason (for failed logins)
failed_attemptsintCount before lockout

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).

-- Recent audit events (last 24 hours)
SELECT *
FROM users_audit_log
WHERE timestamp >= now() - INTERVAL 24 HOUR
ORDER BY timestamp DESC
LIMIT 100
-- All device actions by a specific user
SELECT *
FROM users_audit_log
WHERE event_type = 'device_action'
AND username = 'operator1'
ORDER BY timestamp DESC
-- Failed login attempts from external IPs
SELECT timestamp, username, ip_address,
JSONExtractString(details, 'reason') as reason
FROM users_audit_log
WHERE event_type = 'login_failed'
AND NOT startsWith(ip_address, '192.168.')
AND NOT startsWith(ip_address, '10.')
ORDER BY timestamp DESC
LIMIT 50
-- All firewall changes in the last week
SELECT timestamp, username, event_type, ip_address, details
FROM users_audit_log
WHERE event_type LIKE 'nft_config%'
AND timestamp >= now() - INTERVAL 7 DAY
ORDER BY timestamp DESC
-- User activity timeline
SELECT timestamp, event_type,
JSONExtractString(details, 'mac') as mac,
JSONExtractString(details, 'action_type') as action
FROM users_audit_log
WHERE 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 date
SELECT *
FROM users_audit_log
WHERE 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 addresses
SELECT ip_address, count() as action_count,
groupArray(DISTINCT event_type) as event_types
FROM users_audit_log
WHERE 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_address
HAVING action_count > 10
ORDER BY action_count DESC
-- Bulk action history with affected MAC counts
SELECT timestamp, username,
JSONExtractString(details, 'job_id') as job_id,
JSONExtractString(details, 'action_type') as action_type,
JSONExtractInt(details, 'estimated_macs') as mac_count
FROM users_audit_log
WHERE event_type = 'bulk_action_execute'
ORDER BY timestamp DESC
LIMIT 20
-- Daily action summary by user
SELECT toDate(timestamp) as date,
username,
event_type,
count() as action_count
FROM users_audit_log
WHERE timestamp >= now() - INTERVAL 30 DAY
GROUP BY date, username, event_type
ORDER BY date DESC, username, action_count DESC
-- User management audit trail
SELECT timestamp, username as admin_user,
event_type, target_username, details
FROM users_audit_log
WHERE event_type IN ('user_created', 'user_modified', 'user_deleted',
'account_locked', 'account_unlocked',
'mfa_enabled', 'mfa_disabled')
ORDER BY timestamp DESC
LIMIT 100
-- Configuration change history
SELECT timestamp, username, event_type, ip_address, details
FROM users_audit_log
WHERE event_type IN ('config_changed', 'retention_changed',
'ip_restriction_added', 'ip_restriction_removed')
ORDER BY timestamp DESC

Tip: always include a time-range filter and a LIMIT for interactive queries. The audit log table is indexed on event_type, user_id, and success — filter on those columns whenever possible.

The audit log is also reachable over HTTPS for programmatic export or integration with an external SIEM.

GET /api/audit/logs
ParameterTypeDescription
start_timeISO 8601Start of time range. Optional; defaults to the last 7 days.
end_timeISO 8601End of time range. Optional.
event_typestringFilter by exact event-type string.
searchstringFree-text search across event details.
successboolFilter by success/failure outcome.
limitintMax results (default 100).
offsetintPagination 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:

Terminal window
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.view permission, which by default ships with the admin and operator role sets. The Sessions and Audit Log GUI pages themselves remain admin-only.