Skip to main content

About Okta

Okta is a cloud identity and access management (IAM) platform for managing users, groups, and application access. Serval connects to Okta using OAuth 2.0 client credentials against an Okta API Services app. Once connected, Serval can reach any Okta Management API capability - reading and managing users, groups, and applications, running access reviews, and automating identity lifecycle tasks. Serval also continuously brings your Okta directory into Serval in the background so users, groups, and applications stay up to date. Authentication: OAuth 2.0 client credentials - either a client secret (client_secret_basic) or a private key JWT (private_key_jwt). Data sync: On-demand access to the full Okta Management API from workflows, plus a built-in background directory sync of users, groups (with members), and applications (with their assigned groups). Optionally, Okta event hooks push user and group changes to Serval in real time.

What the Okta integration enables

Anything defined in the Okta Management API can be accessed through Serval.

Get your credentials

Serval connects to an Okta API Services app using OAuth 2.0 client credentials. You can either install Serval from the Okta Integration Network (OIN), which generates credentials for you, or create your own custom Okta API Services app. In both cases you must grant the required scopes on the Okta app and assign the app an admin role so those scopes can actually act on resources. Full provider guidance lives in Okta’s client credentials grant guide.

Connect in Serval

Enter your credentials into the Serval connect form. The same fields are used whether you authenticate with a client secret or a private key - Serval automatically picks the right method based on what you paste into the Client Secret field.
1

API Domain (required)

Your Okta domain without the leading “https://” - for example, “yourcompany.okta.com”. Enter the bare host with no scheme and no “-admin” suffix.
Do not paste the admin console URL. If your console shows “yourcompany-admin.okta.com”, strip the “-admin” and enter “yourcompany.okta.com”. An invalid domain shows: “Must be a valid Okta domain (e.g., yourcompany.okta.com)”.
2

Client ID (required)

The OAuth 2.0 client ID from your Okta application - exactly 20 alphanumeric characters. An invalid value shows: “Must be a valid Okta client ID (20 alphanumeric characters)”.
3

Client Secret (required)

This field is masked. Paste either your plain OAuth 2.0 client secret or the full private key you generated in Okta. Serval automatically uses the private-key method when you paste a key, and the client-secret method otherwise.
When editing an existing connection, you can leave this field blank to keep the stored secret unchanged. The stored secret is always shown masked, never in clear text.
4

Scopes (required)

A comma-separated list of OAuth scopes. Serval pre-fills a default set covering app, user, and group read and manage plus log read. These scopes must also be granted on the Okta app itself. Not all of the pre-filled scopes are required - you can remove any scopes you don’t need.
An empty list is rejected. Each scope must follow the expected format, otherwise you will see: “Each scope must follow the format okta.<resource>.<operation> or okta.<resource>.<subresource>.<operation> (e.g., okta.users.read, okta.accessRequests.catalog.read). SSF scopes are ssf.<operation> (e.g., ssf.read, ssf.manage).”

Verifying the connection

After you connect, Serval runs a series of health checks against your Okta org and reports the result of each one. Each health check is an API call that exercises a specific scope, so the checks always run regardless of which scopes you configured - a check whose scope you removed will simply fail with a missing-scope message. This is expected if you intentionally trimmed the scope list, and you can safely ignore failures for capabilities you don’t plan to use.
  • List Okta Apps confirms Serval can list applications. On success it reports “Successfully listed” followed by the number of apps found. On failure it reports “Unable to list apps.” If the required scope is missing in Serval, it reports “Missing required scope in Serval: okta.apps.read”.
  • List Okta Users confirms Serval can list users. On success it reports “Successfully listed” followed by the number of users found. On failure it reports “Unable to list users.” If the scope is missing, it reports “Missing required scope in Serval: okta.users.read”.
  • List Okta Groups confirms Serval can read groups. On success it reports “Successfully listed” followed by the number of groups found. On failure it reports “Unable to list groups.” If the scope is missing, it reports “Missing required scope in Serval: okta.groups.read”.
  • Manage Okta Groups creates a temporary test group (named with a “serval-healthcheck-” prefix) and immediately deletes it to verify write access. On success it reports “Successfully created and deleted test group:” followed by the test group’s name. On failure it reports “Unable to create and delete groups.” If the scope is missing, it reports “Missing required scope in Serval: okta.groups.manage”.
When a check fails with a permission error, Serval adds: “The correct scope is configured in Serval, but the OAuth application may need admin consent or additional admin roles in Okta.” When Okta returns a server error, Serval adds: “Okta returned a server error. This is likely a temporary issue with Okta’s API - please try again later.”
The most common surprise: the scope is configured correctly in Serval but a check still fails with a permission error. This almost always means the Okta app is missing the admin role (or admin consent). Assign the app an admin role under your admin-role assignments - a scope on its own is not enough.

Real-time sync with event hooks

By default, Serval learns about changes in Okta on the background sync schedule, so a change can take hours to appear. With an Okta event hook configured, Okta notifies Serval the moment a user or group changes, and Serval re-fetches just that user or group - changes typically appear in Serval within seconds. This is optional and additive: the background directory sync keeps running either way, acting as a safety net for anything the event hook misses. No additional OAuth scopes are required - event hooks reuse the same scopes your directory and resource sync already use.
If you don’t see the Webhooks section described below on your Okta application’s Settings tab, make sure user or resource (group) sync is enabled for this Okta app - the section only appears once one of those syncs is turned on. If it’s still missing, contact support@serval.com.
1

Copy the webhook details from Serval

In Serval, go to Applications, open your Okta application, and switch to the Settings tab. The Webhooks section shows two values: a Webhook URL (on Serval’s public API host) and a Secret. Copy both.
The Secret can be re-copied from this page at any time - unlike Okta, Serval does not hide it after setup.
2

Create the event hook in Okta

In the Okta admin console, go to Workflow → Event Hooks and choose Create Event Hook. Give it a name (for example, “Serval real-time sync”) and fill in:
  • URL: the Webhook URL copied from Serval.
  • Authentication field: X-Webhook-Secret
  • Authentication secret: the Secret copied from Serval.
  • Custom header fields: leave empty.
Paste the Secret exactly as copied - no quotes and no trailing whitespace. Serval compares the value character-for-character and rejects anything that doesn’t match.
3

Subscribe to events

The Subscribe to events box starts empty - add the events Serval acts on. Okta lists them by friendly name; these are the ones that trigger a refresh (API event type in parentheses).User events (for user sync):
  • User created (user.lifecycle.create)
  • User activated (user.lifecycle.activate)
  • User deactivated (user.lifecycle.deactivate)
  • User suspended (user.lifecycle.suspend)
  • User unsuspended (user.lifecycle.unsuspend)
  • User’s Okta profile updated (user.account.update_profile)
Group events (for resource sync):
  • Group created (group.lifecycle.create)
  • Group profile updated (group.profile.update)
  • User added to group (group.user_membership.add)
  • User removed from group (group.user_membership.remove)
Any other event types are safely ignored, and any extra user.* or group.* event simply re-fetches that user or group, so subscribing to more does no harm.
4

Verify the hook

Save the hook and click Verify. Okta sends a one-time verification challenge to the Webhook URL, which Serval answers automatically.
The hook shows as “Verified” in Okta. From this point on, changes flow to Serval as they happen.

Gotchas and troubleshooting

Scopes typed into the Serval form are only the scopes requested on the token. They must also be granted on the Okta API Services app, and the app must be assigned an admin role (or a custom role plus resource set). Scopes gate which part of the API is available; the admin role gates which resources can be acted on. Add the missing scope on the Okta app and assign it an admin role under your admin-role assignments.
Serval only connects to “okta.com” and “oktapreview.com” hosts. The connect form’s validation will accept an “okta-emea.com” domain, but requests to EMEA-cell domains will fail once they actually run. Use an “okta.com” or “oktapreview.com” domain.
The API Domain field expects a bare host such as “yourcompany.okta.com”. Do not include “https://”, and do not copy the admin console URL - “yourcompany-admin.okta.com” is wrong; strip the “-admin” to get “yourcompany.okta.com”. The domain is used as both the token host and the API base, so a wrong value breaks everything downstream.
Serval decides between the plain-secret and private-key methods purely by whether the Client Secret value is a key (in JSON form). For key-based authentication, paste the full key into the Client Secret field; anything that is not a JSON key is treated as a plain client secret. The key must be an RSA key - a non-RSA key fails token generation with “key is not an RSA private key”.
Serval does not support DPoP / proof-of-possession. In the custom API Services app’s general settings, uncheck the “Require Demonstrating Proof of Possession (DPoP)” option before connecting, otherwise token use will be rejected.
On update, Serval still requires Scopes, Client ID, and API Domain, but the Client Secret is optional. Leave it blank to keep the existing stored secret unchanged, or paste a new value to replace it. The stored secret is always returned masked.
Okta enforces roughly 250 requests per minute per application on the groups and apps endpoints. Serval paces background syncs to stay under this limit and automatically retries when throttled, but heavy custom workflows against these endpoints can still hit Okta’s rate limits.
Check the URL first: it must be the exact Webhook URL copied from the Webhooks section of your Okta application’s Settings tab in Serval, with no edits. A 404 during verification almost always means the URL is wrong or truncated. If the URL is correct and verification still fails, re-copy the Secret from Serval and re-save the hook - remember it must be pasted exactly into the X-Webhook-Secret authentication field.
Confirm the hook is subscribed to the event types listed in Real-time sync with event hooks - a verified hook with no matching subscriptions delivers nothing useful. Also check Okta’s event hook preview/delivery log to confirm Okta is sending events and receiving successful responses. If deliveries succeed but nothing changes in Serval, the secret may be wrong: Serval acknowledges every delivery (so Okta shows success) but rejects events whose X-Webhook-Secret value doesn’t match. Re-copy the Secret from Serval and update the hook. The scheduled background sync still keeps data correct in the meantime.

Need help? Contact support@serval.com for assistance with your Okta integration.