On This Page

Introduction

To enable customers to leverage a unified platform for enriched, auditable event data, Okta is concentrating its efforts on the new and improved System Log API. Okta plans to eventually deprecate the legacy Events API. We encourage customers to migrate to the new API as it contains a superset of functionality.

This guide aims to help organizations migrate from the Events API to its System Log API replacement. It highlights some of the key structural, semantic, and operational differences (and similarities) between the two APIs to aid in the migration process. We update this guide as the deprecation timeline becomes available.

Note: This guide doesn't attempt to cover specific use cases, detailed patterns of interaction, or the intricacies of particular query parameters. For that, it's suggested to see the corresponding sections in the System Log API documentation. Please note that as of Jan 7, 2019 developers of new projects are unable to access the Events API and should use the System Log API.

Migration

Applications and integrations using the Events API must migrate to the System Log API to continue to operate. You can export the data from the Events API at anytime before the end-of-life (EOL) date. For applications and integrations that need to continue to pull down data from Okta to operate, the following compares the APIs and events to help with the migration.

Key Differences

This section explores the notable differences between the two APIs, the resources and representations they expose, and how they are organized. These differences reflect a complete reimplementation of the system log platform. As a result, one can expect both gross and subtle differences.

Resources

Both of the RESTful APIs provide a single read-only resource:

Events APIs System Log API
GET /api/v1/events GET /api/v1/logs

For brevity, the Events API is often referred to as /events and the System Log API as /logs.

Data Structure

Each of the API resources has an associated data structure, also referred to as the resource "representation" or data model. The System Log API's representation is the LogEvent object. It captures the occurrence of notable system events. The Events API's representation is the Event object. LogEvent has more structure and a much richer set of data elements than Event. It is one of the principal improvements of the System Log API over the Events API.

One of the most important attributes of an event in the Okta system is its "event type" designation. In the Events API, the action.objectType attribute denotes the event type. In the System Log API, the eventType attribute represents the event type. The values in each of these fields are generally different, although there is some overlap for historical purposes. In the interest of easing the transition from the Events API to the System Log API, LogEvent's legacyEventType attribute identifies the equivalent Event action.objectType value. The Event type mapping section of this guide provides a static mapping of Events API event types to System Log API event types.

Another essential difference between the two systems is the manner in which detailed information is encoded. The Events API textually encodes the specifics of a particular event instance into the action.message attribute. This encoding burdened consumers with having to correctly parse data themselves and led to brittleness in downstream systems when wording changed. The System Log API expands and enriches the data model to support storing these values as atomic, independent attributes. Context objects, such as the AuthenticationContext object and GeographicalContext objects, provide attributes that are common across event types. The DebugContext object houses event-type-specific attributes.

Event/LogEvent comparison example

This section illustrates the differences between the Events and System Log data models using a single admin user sign-in event as an example.

Events API event

The following is an example of an Event API successful admin sign-in event instance with the event type app.admin.sso.login.success:

{
   "eventId":"tev2FSkoWAARbKaFBBfPPXUWA1533221531000",
   "sessionId":"102PfloXybbT3q1IOdqDAQoeQ",
   "requestId":"W2Mam7t4pcvodL-w@kNCrQAABSM",
   "published":"2018-08-02T14:52:11.000Z",
   "action":{
      "message":"User logged in to the Admin app",
      "categories":[

      ],
      "objectType":"app.admin.sso.login.success",
      "requestUri":"/admin/sso/request"
   },
   "actors":[
      {
         "id":"00u1qmc3wcC6KIsgi0g7",
         "displayName":"Jane Doe",
         "login":"jdoe@example.com",
         "objectType":"User"
      },
      {
         "id":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3)...",
         "displayName":"CHROME",
         "ipAddress":"99.225.99.159",
         "objectType":"Client"
      }
   ],
   "targets":[
      {
         "id":"00u1qmc3wcC6KIsgi0g7",
         "displayName":"Jane Doe",
         "login":"jdoe@example.com",
         "objectType":"User"
      },
      {
         "id":"0oa1qmc3w1qLYTPVn0g7",
         "displayName":"Okta Administration",
         "objectType":"AppInstance"
      }
   ]
}

The data structure is both narrow in its top-level attributes and shallow in object attribute nesting.

System Log API LogEvent

The following is the corresponding event of a successful user session accessing the admin app as captured in the System Log API with the event type user.session.access_admin_app:

   {
      "actor":{
         "id":"00u1qmc3wcC6KIsgi0g7",
         "type":"User",
         "alternateId":"jdoe@example.com",
         "displayName":"Jane Doe",
         "detailEntry":null
      },
      "client":{
         "userAgent":{
            "rawUserAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3)...",
            "os":"Mac OS X",
            "browser":"CHROME"
         },
         "zone":"null",
         "device":"Computer",
         "id":null,
         "ipAddress":"99.225.99.159",
         "geographicalContext":{
            "city":"Toronto",
            "state":"Ontario",
            "country":"Canada",
            "postalCode":"M6G",
            "geolocation":{
               "lat":43.6655,
               "lon":-79.4204
            }
         }
      },
      "authenticationContext":{
         "authenticationProvider":null,
         "credentialProvider":null,
         "credentialType":null,
         "issuer":null,
         "interface":null,
         "authenticationStep":0,
         "externalSessionId":"102PfloXybbT3q1IOdqDAQoeQ"
      },
      "displayMessage":"User accessing Okta admin app",
      "eventType":"user.session.access_admin_app",
      "outcome":{
         "result":"SUCCESS",
         "reason":null
      },
      "published":"2018-08-02T14:52:11.272Z",
      "securityContext":{
         "asNumber":null,
         "asOrg":null,
         "isp":null,
         "domain":null,
         "isProxy":null
      },
      "severity":"INFO",
      "debugContext":{
         "debugData":{
            "requestUri":"/admin/sso/request"
         }
      },
      "legacyEventType":"app.admin.sso.login.success",
      "transaction":{
         "type":"WEB",
         "id":"W2Mam7t4pcvodL-w@kNCrQAABSM",
         "detail":{

         }
      },
      "uuid":"b5ef15a1-e78f-4125-b425-cc10f04e24f3",
      "version":"0",
      "request":{
         "ipChain":[
            {
               "ip":"99.225.99.159",
               "geographicalContext":{
                  "city":"Toronto",
                  "state":"Ontario",
                  "country":"Canada",
                  "postalCode":"M6G",
                  "geolocation":{
                     "lat":43.6655,
                     "lon":-79.4204
                  }
               },
               "version":"V4",
               "source":null
            }
         ]
      },
      "target":[
         {
            "id":"0ua1qmc3wf2xDawpN0g7",
            "type":"AppUser",
            "alternateId":"unknown",
            "displayName":"Jane Doe",
            "detailEntry":null
         }
      ]
   }

Note the System Log API representation's improved structure and additional embedded information when compared with the Event API's event representation. For example, the System Log API's client.geographicalContext attribute captures the geolocation of the client accessing the system. This attribute is unavailable in the Events API.

Event/System Log API event attribute mapping

Given the above events from each API, the following compares each leaf-level attribute. JSON Pointer notation is used to specify the compared attribute values.

Event LogEvent Notes
/action/categories Always empty
/actors/0/login /actor/alternateId Generally same values
/actors/0/displayName /actor/displayName Generally same values
/actors/0/id /actor/id Generally same values
/actors/0/objectType /actor/type Generally same values
/authenticationContext/authenticationStep New
/sessionId /authenticationContext/externalSessionId New
/actors/1/objectType /client/device Different values
/client/geographicalContext/city New
/client/geographicalContext/country New
/client/geographicalContext/geolocation New
/client/geographicalContext/geolocation/lat New
/client/geographicalContext/geolocation/lon New
/client/geographicalContext/postalCode New
/client/geographicalContext/state New
/actors/1/ipAddress /client/ipAddress New
/actors/1/displayName /client/userAgent/browser New
/client/userAgent/os New
/actors/1/id /client/userAgent/rawUserAgent New
/client/zone New
/action/requestUri /debugContext/debugData/requestUri New
/action/message /displayMessage Generally less content
/action/objectType /eventType Generally contains different IDs (see Event type mappings)
/legacyEventType Contains /action/objectType as its value
/outcome/result Contains a value that is encoded in /action/objectType suffix
/published /published Contains slightly different values
/request/ipChain/0/geographicalContext New
/request/ipChain/0/geographicalContext/city New
/request/ipChain/0/geographicalContext/country New
/request/ipChain/0/geographicalContext/geolocation New
/request/ipChain/0/geographicalContext/geolocation/lat New
/request/ipChain/0/geographicalContext/geolocation/lon New
/request/ipChain/0/geographicalContext/postalCode New
/request/ipChain/0/geographicalContext/state New
/actors/1/ipAddress /request/ipChain/0/ip New
/request/ipChain/0/version New
/securityContext New
/severity New
/targets/0/displayName /target/0/displayName Generally same values
/targets/0/id /target/0/id Generally same values
/targets/0/login /target/0/alternateId Generally same values
/targets/0/objectType /target/0/type Generally same values
/transaction/detail Generally same values
/requestId /transaction/id When /transaction/type is WEB
/transaction/type New
/eventId /uuid Different values
/version New

Note that there is only one actor in the System Log API compared to potentially multiple values in Events API's actors attribute. Instead, the System Log API adds a client attribute to hold any secondary actor to make it easier for consumers to access.

Identity

The identity of a particular event distinguishes it from all other events instances. The Events API encodes this information in the eventId as a 25 character alpha-numeric value with the tev prefix (for example: tev2FSkoWAARbKaFBBfPPXUWA1533221531000). On the other hand, the System Log API represents identity using a completely different scheme in the uuid attribute. As the field name suggests, these are UUIDs (for example: b5ef15a1-e78f-4125-b425-cc10f04e24f3) that are randomly-generated and unique. There is no identity value mapping between corresponding events of the two APIs. As a consequence, you can't infer one from the other.

All other system identifiers are unchanged (for example: user identifiers and application identifiers).

Event types

Event types are the primary method of organization within the Okta event system. They broadly categorize classes of events by an event type identifier. The System Log API has half the number of event types of the Events API. This helps event stream consumers identify and filter events more easily.

Outcome agnostic event types

To the extent possible, event types have removed the logical outcome of the occurrence from the event type ID. For example, the user.session.start event type replaces the following /events equivalents:

  • core.user_auth.login_success
  • core.user_auth.login_denied
  • core.user_auth.login_failed
  • core.user_auth.login_failed.policy_denied
  • core.user_auth.invalid_certificate

Instead, this information has been moved to the body of the event and is encoded in the Outcome object:

{
  "outcome": {
    "result": "FAILURE",
    "reason": "INVALID_LOGIN"
  }
}

This general pattern results in a reduced number of event types making them easier to comprehend and navigate.

Vendor agnostic event types

In /events, there are a multitude of events that include partner specific context information into the message. For example:

  • app.boxnet.api.error.personal_folder_sync_state
  • app.concur.api.error.check_user_exists
  • app.confluence.api.error.get.user

These were primarily used to log errors and create debug context. With /logs, we've used a more generic event (for example, application.call_api) to log a severity "Debug" type message to capture this type of information. If the event is related to an app, that is included in the "target" and can be easily queried and accessed.

Querying

Filtering

Syntactically, filtering between the two APIs is largely unchanged. For example, the filter parameter continues to use the SCIM filter expressions for expressing which events to return by constraining attribute values by various operators. However, the allowable attribute that can be searched is now almost unrestricted. Outside of published, any model attribute that exists can be queried. The following filter illustrates an expression that constrains the value of a sub-attribute:

filter=debugContext.debugData.requestUri eq "/login/do-login"

This opens up many possibilities for selectively retrieving only the data of interest. However, as indicated above, published isn't supported in the filter parameter. To perform temporal filtering, since and until parameters must be used. See Time Range for details.

Furthermore, the new API now supports the co "contains" operator where the specified value must be a substring of the attribute value.

A new "keyword filtering" feature has been introduced through the q parameter.

Time range

In the Events API, there is only one formal query parameter that supports defining the temporal scope of the events returned: startDate. In the System Log API, there is now since (the equivalent of startDate) and a new until parameter that defines the end time bound of the query interval. Both of these operate against the published attribute.

A subtle difference between startDate and since/until is that the former was very liberal in the format that was accepted. In the System Log API, since/until values are required to conform to Internet Date/Time Format profile of ISO 8601. The intention of this requirement is to reduce the risk of format ambiguity (for example: timezone offsets) causing accidental misuse by consumers.

Sorting

Sort ordering by published is now possible through the System Log API sortOrder parameter. When combined with the after parameter, this enables queries to paginate through events in reverse chronological order in a lossless fashion. Paginating in chronological order is possible in both systems.

Note that sort order for polling requests is only approximate. Sort order for non-polling requests is exact. See Polling Requests for details.

Note: The Events API doesn't support custom sorting.

Limits

Both APIs support a limit query parameter that governs the number of events per request to return. In the Events API, the maximum and default value is 1,000 events. The System Log API shares the same maximum value. However, the default value is 100 events. See the limit parameter for details.

Polling

Polling is the process used to reliably ingest data from Okta into an external system. Both APIs use the after parameter in conjunction with Link response headers to safely pull the event stream.

When you first make an API call and get a cursor-paged list of objects, the end of the list is the point at which you don't receive another next link value with the response. This holds true for all but two cases:

  1. Events API: The next link always exists, since the Events API is like a stream of data with a cursor.
  2. System Log API: The next link always exists in polling queries in the System Log API. A polling query is defined as an ASCENDING query with an empty or absent until parameter. Like in the Events API, the polling query is a stream of data.

See Transferring Data to a Separate System and the general information on Link Headers for additional details.

Event type mappings

The listing in the Event type catalog describes the complete relationship between the Events API and System Log API Event type systems. It describes how event types of one system map to the other, making it an invaluable resource for the migration process.

Important: Going forward, the Events API isn't tracking new event types added to the System Log API. For this reason, we highly recommend upgrading to the System Log API.

Resources

This section contains a collection of useful resources that may help in making the switch from /events to /logs.

developer.okta.com

The following are the formal developer documentation pages of each API:

help.okta.com

The following topic provides a list of possible System Log error events that can occur related to provisioning integrations:

support.okta.com

The following are a collection of informational articles that dive into specifics of the System Log and its API:

www.okta.com

The following covers what the System Log is and where to find it, how to translate logs to actual user activity, and how you can leverage the System Log during a security incident. It also reviews some of the actions you can take to respond to an incident identified within the System Log:

github.com/OktaSecurityLabs

The following is a listing of Okta System Log event types of interest for security teams: