Okta System Log Analysis, Step by Step (Free Tool)
Analyze an Okta System Log export in your browser: load the files, read the verdict and findings, pivot on users, IPs and sessions, and export the timeline.
TL;DR. Open the Okta Forensics analyzer, drop your System Log export (JSON, JSON Lines, CSV, gzip, ZIP or a whole folder), and read the verdict: No sign of compromise, Suspicious activity or Likely compromised, with the findings that caused it. Then go through five tabs: Findings (what fired and on which events), Incident timeline, Entities (users, IPs, sessions, factors, apps, admins), All events (filterable, exportable) and Remediation (a checklist ordered by urgency). Nothing is uploaded: the analyzer is Rust compiled to WebAssembly, running in your browser.
This is the "which button do I press" article. For the method behind it (what to look for and why), read the Okta compromise investigation guide first.
Before you start
You need an export of the Okta System Log. The export guide explains the options; the short version is: the whole org, the longest period you have, raw JSON from the API when possible.
No export at hand? Press Try a sample on the home page. It loads a synthetic export of a fictional incident (160 events, invented organisation, documentation-range IP addresses) so you can learn the interface on something that is guaranteed to fire. The fictional incident walkthrough explains every finding it produces.
Step 1: load the files
Drop files on the drop zone, or use Choose files / Choose a folder. What is accepted:
| Input | Notes |
|---|---|
JSON array from /api/v1/logs | several pages in one file are fine |
| JSON Lines, syslog-prefixed lines | one event per line |
| EventBridge, Elastic, Splunk exports | detail, _source, result / _raw envelopes unwrapped |
| CSV | headers must be LogEvent paths (actor.alternateId, target[0].displayName…) or a _raw column; comma, semicolon or tab |
.gz, .zip, folders | decompressed and walked in the browser, nested ZIPs included |
Files are read in 4 MB chunks and streamed to the analyzer, so multi-gigabyte exports work; memory for the events themselves is the real limit. For very large exports (above 200,000 events) the detections still run on every event, but the table lists every piece of evidence plus the most recent events.
Step 2: check what was actually read
Before trusting any verdict, open Files analysed. Each file shows its event count, format and size, plus notes: duplicates removed, records that are not System Log events, invalid JSON, events without a readable timestamp, or a file that ends in the middle of an event (a truncated export). Files not analysed explains every rejection: empty file, not an Okta log, a spreadsheet instead of CSV, a broken gzip or ZIP.
Then look at the statistics row: events, users, IP addresses, sessions, and the period (UTC). If the period is not what you exported, stop and fix the export.
Step 3: read the verdict
The verdict logic is deliberately simple and visible:
| Verdict | Rule |
|---|---|
| Likely compromised | any critical finding, or high findings from two different rules |
| Suspicious activity | any other high or medium finding |
| No sign of compromise | nothing above low (low findings are informational) |
Under Why, the findings that drove the verdict are listed. A clean verdict means none of the 25 detection rules matched these events. It is not a certificate; the limitations article explains what can be missed.
Step 4: review the findings
Each finding card shows a severity (critical, high, medium, low), an escalated badge when a follow-up condition raised it (for example a push flood followed by an accepted push), a sentence built from the evidence, first and last timestamps, the users and IPs involved, the MITRE ATT&CK techniques, and Show events to open the evidence in the event table.
What each family means is covered in its own article:
- MFA prompts and resets: MFA fatigue, helpdesk social engineering
- Sessions: session hijacking
- Admin and persistence: roles and API tokens, identity providers
- Sign-in attacks: password spraying
When a sensitive application (AWS, Microsoft 365, Google Workspace, GitHub, Kubernetes platforms…) was opened after suspicious activity, the finding links to the sibling tool that reads that platform's logs, for example AWS Forensics for CloudTrail.
Step 5: walk the incident timeline
The Incident timeline tab orders the evidence of every medium, high and critical finding, plus the admin actions of the accounts involved, in time order. This is the draft of your report's chronology. Switch between UTC and Local time with the toggle; keep UTC for anything you share.
Step 6: pivot on entities
The Entities tab lists users, IP addresses (with ASN and country), sessions, factors, apps and admins, each with event and failure counts, first and last seen, and the findings they appear in. Click Events on any row and the event table is filtered to that entity. This is how you answer "what else did this IP do?" or "what happened in this session?" without writing a query.
Step 7: filter and export the events
All events combines a free-text filter (user, IP, eventType, app, session, date), a category filter (authentication, MFA, sessions, admin and IdP, policies, app access…), an outcome filter, and In a finding only. Click a row to see every field that matters: message, outcome, actor, targets, client, network, session, factor, privilege granted, risk, behaviors, anonymizer tunnel, ThreatInsight flag, request URI, transaction and uuid.
CSV and JSON export what is currently filtered. The CSV is protected against formula injection, so it is safe to open in a spreadsheet.
Step 8: remediate
The Remediation tab turns the findings into a checklist ordered by urgency: preserve the logs, clear sessions, reset factors and passwords, review and revoke admin roles, revoke API tokens, remove unknown identity providers, restore policies, investigate downstream applications. Tick items as you go (the state stays in the page only). The "What to do next" block points to Okta's own security guidance.
Privacy, briefly
The logs contain personal data. That is why the analyzer has no upload endpoint: files are read locally in a Web Worker, parsed by WebAssembly, and the results live in the page. Closing the tab discards them.