製品
Oktaのプラットフォームは、AIエージェントから顧客、従業員やパートナーまで、あらゆるタイプのアイデンティティを保護します。
In this guide we will discuss the various types of data that can be retrieved from Okta, the potential business value of this data and how to effectively interact with this data.
Okta is the secure foundation for connections between people and technology. With offerings like Single Sign-on (SSO), Lifecycle Management (LCM), Adaptive Multi-Factor Authentication (MFA), Universal Directory (UD) and API Access Management, Okta is a cloud enabling platform that is paving the way for fast and wide adoption of cloud services in the enterprise. The power of Okta’s core identity services are also available to software developers and integrators through our developer platform product
Using our logs, you can ingest activities flowing through Okta for the purposes of:
John DoeJonathan DoeJdoejohn.doeBuild an integration using these guidelines and following the requirements below
Submit a request to Okta’s partner team to have your integration reviewed
Engage in joint go-to-market opportunities
Okta has well documented public API endpoints, In this document, we will discuss partner integration guidance that builds on that documentation.
All configurations will need to provide a customer the ability to define their base URL and API key. The base URL will be used as the basis for building organization specific RESTful URLs and the API key is included in the Authorization header of requests to authenticate the interaction. The API key is to be considered extremely sensitive and controls should be put in place to protect it in the same manner that a password would be protected.
Learn more in the following links:
To provide for visibility into usage patterns and adoption of integrations we require partners to use a distinct and agreed upon User-Agent string. Generally, this would look something like:
Example 1
{company}/{version}Example: Acme/1.1
Example 2
{product}/{version}Example: SuperSIEMNexGen/2.0
Please work with us to register and track the integration.
Learn more in the following links:
Most queries to endpoints that returns lists will require support for pagination. Support for pagination must be incorporated into all development. Different endpoints will have different suggested page sizes. Please refer to the endpoint specific documentation below for that guidance.
Learn more in the following links:
429) are returned to calling clients when rate limits are exhaustedLearn more in the following links:
To protect both parties from wasting resources we have recommended guidelines for polling intervals and default filters to apply. Please refer to the Best Practices sections for each endpoint to review the guidance specific to that endpoint.
| Endpoint | User Agent | Page Size | Interval | Delta Polling | Rate Limited | More Resources |
|---|---|---|---|---|---|---|
| Logs | Required | 100 | 300 | Yes | Yes (60/Minute) | System Log API |
| Users | Required | 200 | 86400 | Yes | Yes | Users API |
| Groups | Required | 1000 | 86400 | Yes | Yes | Groups API |
| Apps | Required | 20 | 86400 | No | Yes | Apps API |
| appUsers | Required | 20 | - | No | Yes | appUser Object |
| appGroups | Required | 20 | - | No | Yes | appGroup Object |
When interacting with Okta there are a variety of different types of data you can retrieve and interact with. This document is structured in such a way that each different data type is described individually by the endpoint (URI) that is used to interact with it.
Our System Log API is a recent addition that improves upon our Events API.
Among other things it provides:
See the reference section at the end of the document for information on migrating from the Event API to the System Log API.
Data provided from this endpoint includes but is not limited to.
Authentication events, user profile updates, user state changes, application and group assignment, Okta platform changes and more. Each log clearly describing the actor, action, targets and context of the event.
This endpoint is most relevant for a SIEM, UEBA or CASB looking to ingest activity from. Other specialized cases exist where tightly scoped queries are made to detect a specific condition or an Ad hoc query to provide enriched context to an incident (security or operational) investigation. An example of such a use case is elaborated in a recent blog post
In addition to the Common Guidance offered above the System Log API carries these unique guidelines.
The page size (limit parameter) should be a configurable value with a range between 10 and 100, the default value should be 100.
For ongoing polling, the of collection should be configurable. Regular polling for new logs is preferred, a suggested default interval between 60 and 300 seconds is encouraged. A maximum interval of 1 day should be enforced.
for Ad hoc queries, crafting a tightly scoped filter and specifying start and end dates to reduce the data overhead associated with trying to do client side filtering.
This approach is intended to address the use-case of the SIEM, UEBA or other external system that aims to ingest all event data from Okta as efficiently as possible. This is accomplished in 2 phases
This demonstrates logic to deal with pagination aware cold and warm start collection
Pseudocode (pythonish)
since = ISO8601 date/time
limit = configurable page size
# check for an existing checkpointUrl
if checkpointUrl:
# This is a warm start, picking up from where we left off
url = checkpointUrl
else:
# This is a cold start, use configuration values
myOkta = "yourOktaDomainName"
myLimit = 100
mySince = "2017-10-01T00:00:00.000Z"
# your http client library of choice will probably do this part for you
url = "https://" + myOkta + "/api/v1/logs"
url += "?since=" + mySince
url += "&limit=" + myLimit
# collect data and all available pages
while url:
response = GET url
results += response.json()
# determine if there are more pages to collect
if len(response.json()) = myLimit and 'next' in response.links
# extract the next link from the response
url = response.links['next']['url']
elif len(response.json()) = 0:
# if this request returned 0 results there is no next link contained
# use the same as the checkpointUrl for the next iteration
checkpointUrl = url
url = false
else:
# if this request returned fewer results than requested
# use the next link contained in the response for the next iteration
checkpointUrl = response.links['next']['url']
url = false
# store the data collected during this interval
store results
# save the checkpointUrl for future iterations
save checkpointUrl
This approach is intended to one-off collection of specific events tightly filtered by date, a filter, a query or any valid combination of these as described here
fetch all events occurring in the last 7 days with a specific eventType
Pseudocode (pythonish)
limit = configurable page size
eventType = a specific event type
myOkta = "yourOktaDomainName"
myLimit = 100
myEventType = "user.session.start"
url = "https://" + myOkta + "/api/v1/logs"
url += "?limit=" + myLimit
url += '&filter=(eventType eq "' + myEventType + '")'
# collect data and all available pages
while url:
response = GET url
results += response.json()
# determine if there are more pages to collect
if len(response.json()) = myLimit and 'next' in response.links
# extract the next link from the response
url = response.links['next']['url']
else:
# if this request returned fewer results than requested we are done
url = false
# store the data collected during this interval
store results
fetch the most recent 1000 events or 7 days worth of events for a specific user
Pseudocode (pythonish)
limit = configurable page size
userId = a specific user of interest
now = now()
then = now.addDays(-7)
myOkta = "yourOktaDomainName"
myLimit = 100
mySince = then.toISO8601() #"2017-10-01T00:00:00.000Z"
myUntil = now.toISO8601() #"2017-10-08T00:00:00.000Z"
myUserId = "john.doe"
url = "https://" + myOkta + "/api/v1/logs"
url += "?limit=" + myLimit
url += "&since=" +mySince
url += "&until=" +myUntil
url += "&sortOrder=DESCENDING"
url += '&filter=(actor.alternateId eq "' + myUserId + '")'
# collect data and all available pages
while url:
response = GET url
results += response.json()
# determine if we have already collected 1000
if len(results) >= 1000
url = false
# determine if there are more pages to collect
elif len(response.json()) = myLimit and 'next' in response.links
# extract the next link from the response
url = response.links['next']['url']
else:
# if this request returned fewer results than requested we are done
url = false
# store the data collected during this interval
store results
More details and complete examples are available in our System Log API documentation as well as our ISV Syslog References guide
At the heart of the Okta Identity Cloud is the User object. This object exhaustively describes the user including:
This information can provide value to any integration seeking to provide user context.
In addition to the Common Guidance offered above the Users API carries these unique guidelines.
The page size (limit parameter) should be a configurable value with a range between 10 and 200, the default value should be 200.
The interval of ongoing polling should be configurable. Frequent polling of user objects is generally discouraged and only warranted with strict stipulations described below. While user objects and associated profiles are volatile they are not fluid. Consider the cost/benefit associated with queries you perform.
If your goal is to populate and synchronize an external system with Okta identities a SCIM integration might be warranted. Please review our SCIM Standards documentation resource for more information.
When using the API to sync user data with an external system keep in mind the desired outcome of the integration and perform delta queries using the most appropriate date filter, or query the Logs API to watch for user authentication, lifecycle and profile events.
| field | associated eventType | Note |
|---|---|---|
| created | user.lifecyle.create | When the user was created |
| activated | user.lifecycle.activate | When the user was last activated |
| statusChanged | user.lifecycle.* | the timestamp of the most recent state change |
| passwordChanged | user.account.update_password | the timestamp of the most recent password |
| lastUpdated | user.account.update_profile or any from above | the timestamp of the most recent profile, password or state change |
| lastLogin | user.authentication.auth* | the timestamp of the most recent |
When polling for users, queries should be date driven using the search and filter capabilities:
?filter=lastUpdated gt {startDate}
startDate being the time of the last polling intervallastUpdated can be replaced with the most granular date attribute from the list above to suite your specific needs.With proper filtering the interval used becomes less of an issue, as an integration only interested in credential changes or login activity should filter accordingly and ignore irrelevant churn.
Synchronization jobs should, at a minimum, introduce filters on lastUpdated to ongoing queries to minimize needless sifting.
In addition to the attributes discussed in the filtering guidelines above the User object has a status attribute. Refer to the online documentation describing the controlling state machine.
A Universal Directory enabled Okta Org features an extensible schema with the ability to source and master data from many sources including Applications and Directories. Information related to the user’s organizational role, hierarchy, geographic location and more can be found in the user profile. The schema is extensible and the level of detail contained is based entirely on the customer’s implementation.
The default attributes of a user are aligned with core SCIM attributes and listed here.
Use the q (query) parameter to search across multiple attributes to find users
Request
GET https://{yourOktaDomain}.com/api/v1/users/?q=John
Response
[
{
"id": "00u1aq5mpenI88ZEn1d8",
"status": "ACTIVE",
"lastUpdated": "2017-04-17T23:16:50.000Z",
"...":"...",
"profile":
{
"firstName": "John",
"lastName": "Doe",
"login": "jdoe@domain.tld",
"email": "Joh.Doe@company.tld",
"...": "..."
},
"...": "..."
},
{},
]
Use the q (query) parameter to search across multiple attributes to find users Use our filter and search capabilities to locate users with greater accuracy and flexibility.
Request
GET https://{yourOktaDomain}.com/api/v1/users/?filter=(profile.firstName eq "John" AND profile.lastName eq "Doe")
Response
[
{
"id": "00u1aq5mpenI88ZEn1d8",
"status": "ACTIVE",
"lastUpdated": "2017-04-17T23:16:50.000Z",
"...":"...",
"profile":
{
"firstName": "John",
"lastName": "Doe",
"login": "jdoe@domain.tld",
"email": "Joh.Doe@company.tld",
"...": "..."
},
"...": "..."
}
]
Retrieve a single user based on the user’s:
Using Get User
Request(s)
#by Short userName
GET https://{yourOktaDomain}.com/api/v1/users/jdoe
#by Full userName
GET https://{yourOktaDomain}.com/api/v1/users/jdoe@domain.tld
#by Okta id (uid)
GET https://{yourOktaDomain}.com/api/v1/users/00u1aq5mpenI88ZEn1d8
Response
{
"id": "00u1aq5mpenI88ZEn1d8",
"status": "ACTIVE",
"lastUpdated": "2017-04-17T23:16:50.000Z",
"...":"...",
"profile":
{
"firstName": "John",
"lastName": "Doe",
"login": "jdoe@domain.tld",
"email": "Joh.Doe@company.tld",
"...": "..."
},
"...": "..."
}
More details and complete examples are available in our Users API documentation.
Groups are a first-class citizen in the Okta environment. All the standard uses of Groups are leveraged within Okta and subsequently extended to orbiting applications and directories. They serve purposes including but not limited to:
In addition to the Common Guidance offered above the Groups API carries these unique guidelines.
The page size (limit parameter) should be a configurable value with a range between 100 and 10000, the default value should be 10000.
The interval of ongoing polling should be configurable. Frequent polling of group objects is generally discouraged and only warranted with strict stipulations described below.
When using the API to sync group data and group membership information with an external system keep in mind the desired outcome of the integration.
Tightly tied to the interval used is the idea of doing date bound queries to retrieve delta datasets. There are two Date fields available to determine changes to a group.
lastUpdated is the timestamp when a group’s profile was last updatedlastMembershipUpdated is the timestamp when a user was last added to or removed from that groupThese values change independently. Membership changes will not modify the lastUpdated timestamp.
When polling for groups and group changes, queries should be date driven using the search and filter capabilities:
?filter=lastMembershipUpdated gt {startDate}
startDate being the time of the last polling intervallastMembershipUpdated can be replaced with the the most granular date attribute from the list above that suites your specific need.With proper filtering the interval used becomes less of an issue, as an integration only interested in group membership changes would filter accordingly and ignore irrelevant churn.
Synchronization jobs should, at a minimum, introduce filters on lastMembershipUpdated.
In addition to hosting native groups, Okta can source and replicate group membership between directories and apps. Every group object in Okta will contain a Type property that describes the source of the group. The profile of a group will vary based on the source of the group. Different app groups have different profiles.
Groups will always have a name, description and sufficient context to identify and associate back to their source. For example: An Active Directory group has an externalId attribute that is the AD groups Object-Guid.
Group membership manipulation is the de facto standard for affecting user entitlements and restrictions including but not limited to:
Using Get Group you can also add a query parameter expand with a value of app and or stats. The result is a single call with additional details about the group. This method works when getting a singular group by id and when listing groups with or without a filter or query applied.
Request
# ALL groups
GET https://{yourOktaDomain}.com/api/v1/groups?limit=100&expand=app,stats
# Groups matching filter criteria
GET https://{yourOktaDomain}.com/api/v1/groups?filter=lastMembershipUpdated gt 2017-04-17T23:16:50.000Z &expand=app,stats
# Specific group based on Group ID (gid)
GET https://{yourOktaDomain}.com/api/v1/groups/00gwy337uaRYJVHTHACG?expand=app,stats
Response
[
{
"id": "00gwy337uaRYJVHTHACG",
"lastUpdated": "2017-03-31T23:16:50.000Z",
"lastMembershipUpdated": "2017-04-17T23:16:50.000Z",
"...": "...",
"type": "APP_GROUP",
"...": "...",
"profile": {
"name": "Domain Group 1",
"...": "...",
"externalId": "nYGCoOeiW0uRVHW3MQcB1Q=="
},
"_embedded": {
"app": {
"id": "0oarja7d8gWSEGZBPZVB",
"name": "active_directory",
"...": "..."
},
"stats": {
"usersCount": 301,
"appCount": 0,
"groupPushMappingsCount": 0,
"...": "..."
}
},
"...": "..."
},
{}
]
Using the same logic described online in List Group Members you can retrieve a list of users in each group. Hint: use the group._embedded.stats.usersCount value to know if *ANY* users are assigned
If your integration doesn’t need credential and credential provider related details when listing group members use the “skinny_users” endpoint, it operates in the same manner as the “users” endpoint with the following differences in the resulting data object
credentials.provider object missing_links object only contains .self referenceRequest
# ALL groups
# Get members using Skinny Users endpoint
GET https://{yourOktaDomain}.com/groups/00gwy337uaRYJVHTHACG/skinny_users
# Get members using the regular Users endpoint
GET https://{yourOktaDomain}.com/api/v1/groups/00gwy337uaRYJVHTHACG/users
Response
[
{
"id": "00u10eqzrjiGORRUNTBM",
"status": "ACTIVE",
"created": "2015-01-07T01:52:51.000Z",
"...": "...",
"profile": {
"login": "jsmith@oktaprise.com",
"email": "jane.smith@oktaprise.com",
"...": "..."
},
"credentials": {
"recovery_question": {
"question": "What is the name of your first stuffed animal?"
}
},
"_links": {
"self": {
"href": "https://oktaprise.okta.com/api/v1/users/00u10eqzrjiGORRUNTBM"
}
}
},
{
"id": "00u10h0t5suAYARMBTGF",
"status": "ACTIVE",
"created": "2015-01-09T05:28:55.000Z",
"...": "...",
"profile": {
"login": "jdoe@oktaprise.com",
"email": "joshua.kroeze@oktaprise.com",
"...": "..."
},
"credentials": {
"recovery_question": {
"question": "What was the first thing you learned to cook?"
}
},
"_links": {
"self": {
"href": "https://oktaprise.okta.com/api/v1/users/00u10h0t5suAYARMBTGF"
}
}
}
]
Using the logic described online with List Assigned Applications you can retrieve a collection of applications that are assigned based on membership of that group. Hint: Use the group._embedded.stats.appsCount value discussed above to know if *ANY* apps are assigned
Request
GET https://{yourOktaDomain}.com/api/v1/groups/00gwy337uaRYJVHTHACG/apps
Response
[
{
"id": "0oa9lv1b0tRF7p34K0h7",
"name": "scim2headerauth",
"label": "SCIM 2.0 Test App (Header Auth)",
"status": "ACTIVE",
"...": "...",
},
{
"id": "0oa9sieay0Tju66dM0h7",
"name": "github_enterprise",
"label": "GitHub Business2",
"status": "ACTIVE",
"...": "...",
},
{
"id": "0oaa097p4wlH2q8To0h7",
"name": "servicenow_ud",
"label": "ServiceNow UD",
"status": "ACTIVE",
"...": "...",
}
]
Methods of, and reasons to, manipulate Groups and Group membership are discussed in our “Write back to enforce policy in Okta” Groups section below.
More details and complete examples are available in our Groups API documentation.
Apps are the representation of an application or directory source or target in Okta. Specific application attributes are defined on an app by app basis. Through the Apps endpoint you gain additional insight into who a user is across the ecosystem. We also see the meaning behind a group and the roles and entitlements it describes.
In addition to the Common Guidance offered above, the Apps API carries these unique guidelines.
The page size (limit parameter) should be a configurable value with a range between 10 and 100. The default value should be 20.
The interval of ongoing polling should be configurable. Frequent polling of apps can provide little value on its own. While not resource intensive it should be understood that application additions and changes are infrequent operations, as such an interval minimum of daily should be acceptable.
Further guidance about resources inside of the Apps endpoint are discussed in the AppUsers and AppGroups sections below.
The application data model is described in detail here
Here we will draw attention to a few App attributes and their meaning in the context of a security analytics integration:
features
signOnMode
credentials.scheme
using a filter on the status attribute to retrieve a list the active Applications
Request
GET https://{yourOktaDomain}.com/api/v1/apps?filter=status eq "ACTIVE"
Response
[
{
"id": "0oa8tvgiuh93NlQ0W0h7",
"name": "zendesk",
"label": "Zendesk",
"status": "ACTIVE",
"lastUpdated": "2016-11-20T04:01:19.000Z",
"...": "...",
"features": [
"PUSH_NEW_USERS",
"PUSH_USER_DEACTIVATION",
"IMPORT_USER_SCHEMA",
"REACTIVATE_USERS",
"PUSH_PROFILE_UPDATES",
"IMPORT_NEW_USERS"
],
"signOnMode": "SAML_2_0",
"...": "..."
},
{
"id": "0oa11hz4wq4dioDw91e8",
"name": "bluejeans",
"label": "BlueJeans",
"status": "ACTIVE",
"lastUpdated": "2015-04-17T19:27:36.000Z",
"...": "...",
"signOnMode": "BROWSER_PLUGIN",
"credentials": {
"scheme": "EDIT_USERNAME_AND_PASSWORD",
"userNameTemplate": {
"template": "${source.login}",
"type": "BUILT_IN"
},
"revealPassword": true,
"signing": {
"kid": "..."
}
},
"...": "..."
}
]
More details and complete examples are available in our Apps API documentation.
Like the User object discussed previously the appUser object is an extensible and information rich data source. The appUser object is a representation of a user’s profile specific to the associated application or directory and can include profile data, role, license information and more depending on the containing application.
In addition to the Common Guidance offered above, the appUser object carries these unique guidelines.
The page size (limit parameter) should be a configurable value with a range between 10 and 100, the default value should be 20.
A specific need should be present before polling the information present. The data models of appUser objects vary by application and implementation.
If full profile data isn’t required make use of the “skinny_user” variant. This endpoint operates in the same manner as the “users” endpoint but is optimized for speed and efficiency returning a minimized response object.
Refer to the appUser Object data model for an elaboration of the appUser data structure.
Using this method you can list the user assigned to an app which will include their appUser profile.
Request
# ALL users using skinny_users endpoint
GET https://{yourOktaDomain}.com/api/v1/apps/{app_id}/skinny_users
# ALL users using the users endpoint
GET https://{yourOktaDomain}.com/api/v1/apps/{app_id}/users
# Specific User using their Okta User ID (uid)
GET https://{yourOktaDomain}.com/api/v1/apps/{app_id}/users/{user_id}
Response
[
{
"id": "00u8tvvbi3eihn3Ur0h7",
"externalId": "15467658348",
"created": "2016-11-20T04:04:42.000Z",
"lastUpdated": "2016-11-20T23:09:40.000Z",
"scope": "GROUP",
"status": "PROVISIONED",
"statusChanged": "2016-11-20T04:04:44.000Z",
"syncState": "SYNCHRONIZED",
"lastSync": "2016-11-20T23:09:40.000Z",
"credentials": {
"userName": "nick@mytest.oktapreview.com"
},
"profile": {
"Role": "agent",
"phone": "555-789-1231",
"Groups": [
"Support"
],
"alias": "Nick",
"Organization": "mattegantest",
"locale": "English",
"RestrictionId": "all",
"timeZone": "Pacific Time (US & Canada)",
"firstName": "Joeseph"
}
},
{}
]
Using this Method, you can make a single call to retrieve a collection of all application objects with an appUser object – as shown above – nested within each Application in the _embedded object. This approach will reduce the need to make iterative calls to fully elaborate a user’s application footprint.
Request
#Retrieve all Apps with Embedded appUser objects for given user
GET https://{yourOktaDomain}.com/api/v1/apps?filter=user.id eq "00u1a7q3KgTkZE1d8"&expand=user/00u1a7q3KgTkZE1d8
Response
[
{
"id": "0oa8tvgiuh93NlQ0W0h7",
"name": "zendesk",
"label": "Zendesk",
"status": "ACTIVE",
"..": "...",
"_embedded": {
"user": {
"id": "00u1a7q3KgTkZE1d8",
"externalId": "Matt.Egan@oktaprise.com",
"...": "...",
"profile": {
"appProperty": "Value",
"appRole": [ "role1","role2" ]
}
}
}
},
{}
]
More details and complete examples are available in our appUser Object documentation.
You can gain a better understanding of the meaning of groups in Okta by looking at the appGroups endpoint. For example, you can infer risk scores based on the access granted to a user from a given group.
The page size (limit parameter) should be a configurable value with a range between 10 and 100, the default value should be 20.
Like the guidance given for polling applications, the volatility of groups used to assign applications is low. Daily intervals should suffice in most cases.
Refer to the appGroup Object data model for an elaboration of the appGroup data structure.
Using this method you can list the groups used to assign the specified app along with any application properties defined as a function of being assigned through that group.
Request
#Retrieve all Apps with Embedded appUser objects for given user
GET https://{yourOktaDomain}.com/api/v1/apps/{app_id}/groups
Response
[
{
"id": "00gbo36oc0GUPcc020h7",
"lastUpdated": "2017-08-16T23:06:52Z",
"priority": 0,
"profile": {
"time_zone": "US/Pacific",
"cost_center": "Cost Center X",
"department": "Department Y",
"company": "Company Z"
},
"...": "..."
},
{
"id": "00gc96o9g6CY9M7N00h7",
"lastUpdated": "2017-10-02T20:06:02Z",
"priority": 1,
"profile": {
"time_zone": "US/Pacific",
"cost_center": "Cost Center A",
"department": "Department B",
"company": "Company C"
},
"...": "..."
}
]
More details and complete examples are available in our appGroup Object documentation.
Building from the foundation laid in this guide
To resolve an incident or mitigate a perceived threat, an external system may want to affect a user’s state, modify authentication policies or reduce application availability. This Security Enforcement guide will describe how and when a system might take these actions.