In the Okta Admin Console, Reports → System Log lets you search events and download the results. For JSON, use the System Log API: GET /api/v1/logs with since and until, following the next link until it runs out. A short script is below. Okta keeps System Log events for 90 days.
When identity is the perimeter, Okta’s System Log is the gate log. It records every sign-in, every MFA push, every factor reset and every admin role change. Prime Core has 58 detection rules for Okta data, mapped to 32 MITRE ATT&CK techniques. Among them: password spraying (T1110.003), MFA fatigue (T1621) and attackers tampering with MFA enrollment (T1556.006).
Before you start
Retention is 90 days. Anything older exists only where you’ve been streaming or forwarding Okta logs, such as a SIEM.
You need a token. An API token (Security → API → Tokens) inherits the permissions of the admin who created it. A read-only admin is enough for logs. For anything automated, an OAuth service app with the okta.logs.read scope is the cleaner choice. Either way, the token is a credential. Keep it out of shell history and revoke it when you’re done.
Rate limits apply. The logs endpoint has its own rate limit. Big windows are fine, just not instant.
Export with the System Log API
This Python script pages through a time window and writes one event per line. It needs requests (pip install requests):
import json, os, requests
org = "https://yourorg.okta.com"
headers = {"Authorization": f"SSWS {os.environ['OKTA_TOKEN']}", "Accept": "application/json"}
url = f"{org}/api/v1/logs"
params = {"since": "2026-10-19T00:00:00Z", "until": "2026-10-20T00:00:00Z", "limit": 1000}
with open("okta_1019.jsonl", "w") as out:
while url:
r = requests.get(url, headers=headers, params=params, timeout=60)
r.raise_for_status()
events = r.json()
for e in events:
out.write(json.dumps(e) + "\n")
if not events:
break
url = r.links.get("next", {}).get("url")
params = None # the next link already carries the query
Always set until. Without it, Okta treats the request as a live poll and keeps handing back a next link. Your loop would run forever, waiting for new events.
To narrow it down, add a filter to params, for example “filter”: ‘eventType eq “user.session.start”‘. Or use “q”: “jane” for a keyword search.
What to look for
| eventType | Why it matters |
|---|---|
| user.session.start with outcome.result: FAILURE | Failed sign-ins; many users from one IP range means spraying |
| user.mfa.okta_verify.deny_push | User rejected a push; a burst of these is MFA fatigue in progress |
| user.mfa.factor.deactivate, user.mfa.factor.reset_all | Factors removed, often right after a helpdesk social-engineering call |
| user.account.privilege.grant | Admin role granted |
| policy.rule.update, policy.lifecycle.update | Sign-on or MFA policy changed, possibly weakened |
| system.api_token.create | A new API token, a quiet way to keep access |
The fields that tell the story: actor.alternateId (who), client.ipAddress and client.geographicalContext (from where), outcome (what happened), and debugContext.debugData (the details).
Upload, sanitize and review in LogTotal
- Upload. Open logtotal.com and drop in the .jsonl file. [PROOF: upload screen, size limit]
- Sanitize. [PROOF: what gets masked: usernames and emails, IPs, device and session IDs]. Look it over before you continue.
- Review. [PROOF: what the results screen shows]
When it goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 | Wrong or revoked token, or a missing SSWS prefix | Check the header format; create a new token |
| 403 | Token creator lacks rights to read logs | Use a token from an admin with log access |
| 429 | Rate limit hit | Wait for the time in X-Rate-Limit-Reset, then continue |
| The script never finishes | No until in the query | Set until |
| Nothing older than 90 days | Okta retention | Check your SIEM or log streaming destination |
FAQ
Can’t I just use the Admin Console?
For a quick look at a short window, yes. For anything you want to analyze or keep, the API gives you complete JSON with every field.
Does this cover Auth0?
No. This guide is about Okta Workforce Identity. Auth0 has its own log format and API.