Skip to content

feat(okta): add System Log, MFA, sessions, apps, roles, and group rules - #6741

Merged
waleedlatif1 merged 6 commits into
stagingfrom
feat/okta-depth
Aug 15, 2026
Merged

feat(okta): add System Log, MFA, sessions, apps, roles, and group rules#6741
waleedlatif1 merged 6 commits into
stagingfrom
feat/okta-depth

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Extends Okta from 18 to 44 tools: System Log, MFA factors, sessions, applications, admin roles, and group rules
  • Retrofits cursor pagination onto the three pre-existing list tools (list_users, list_groups, list_group_members). Purely additive — every existing output field keeps its name, type, and mapping; the change adds an after cursor param plus nextCursor/hasMore outputs. Verified by diffing each tool against the branch point
  • All 8 list tools now paginate identically through a shared parseOktaPagination helper that reads Okta's opaque after cursor from the Link: rel="next" header (Okta never returns the cursor in the body — the response is a bare JSON array, and the absence of that Link entry is what marks the last page)
  • Factors and admin roles are intentionally not paginated: those endpoints return the full set with no Link header
  • Consolidates the repeated auth-header and error-parsing blocks into shared oktaHeaders / throwOktaError helpers

Doc contradictions resolved

Three places where Okta's prose docs disagree with the bundled OpenAPI 3 spec (v5.1.0). The spec won in each case:

  • There is no factor-level lifecycle/reset path. Resetting one factor is DELETE /users/{id}/factors/{factorId}; resetting all is POST /users/{id}/lifecycle/reset_factors
  • removeRecoveryEnrollment is a query param on the single-factor DELETE, not on the reset-all endpoint
  • Group-rule people conditions have exclude only — there is no include counterpart on either the users or groups condition

Verification scope

The whole audit is spec-derived. Nothing here ran against a live Okta org, so endpoint shapes and response fields are backed by the OpenAPI spec rather than observed payloads.

  • Drops non-numeric limit/priority input instead of coercing it to NaN (which serialized to null and produced a misleading Okta validation error)

Type of Change

  • New feature

Testing

Added apps/sim/tools/okta/utils.test.ts covering the Link-header cursor parser (next / self-only / absent / malformed) and the group-rule flattener. Verified the tests fail when the rel="next" pattern is broken.

Validated against the bundled Okta OpenAPI 3 spec (v5.1.0). Confirmed 44/44 tools registered and present in all three generated artifacts, no duplicate subBlock ids in the block, pagination params and outputs consistent across all 8 list tools, biome clean, and no new type errors.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 15, 2026 11:47pm

Request Review

@cursor

cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Large expansion of identity and access management APIs, including destructive actions (session revocation, MFA reset, app unassignment, admin role changes) validated primarily against OpenAPI rather than live Okta.

Overview
Expands the Okta integration from 18 to 44 workflow operations, covering group rules, MFA factors, sessions, applications, admin roles, and System Log queries—in addition to the existing user/group lifecycle actions.

Cursor pagination is added across eight list operations (after input, nextCursor / hasMore outputs), including retrofits for list users, groups, and group members.

The Okta block gains matching operations, subBlocks, canvas sentences, wand prompts for search/filter/expressions, AuthMode.ApiKey, and a stricter params transform that drops blank fields on partial updates and invalid numeric limit/priority instead of sending NaN/null to Okta. Block outputs are broadened for new response shapes (e.g. events at top level, not nested targets/debugData).

Docs (okta.mdx) and integrations.json are updated to describe the new surface. okta.test.ts locks param-merge behavior for the block transform.

Reviewed by Cursor Bugbot for commit cc1976b. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR substantially expands the Okta integration with tools for System Log events, MFA factors, sessions, applications, roles, and group rules.

  • Adds shared Okta authentication, error handling, pagination, and response-shaping utilities.
  • Adds cursor pagination to existing and new list operations.
  • Updates the Okta block, registries, generated metadata, documentation, and focused tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/okta.ts Expands the Okta block configuration and correctly drops invalid numeric inputs through the params transform.
apps/sim/tools/okta/utils.ts Centralizes Okta headers, error parsing, pagination parsing, and shared response transformations.
apps/sim/tools/okta/utils.test.ts Covers pagination-header parsing and group-rule response flattening.
apps/sim/blocks/blocks/okta.test.ts Verifies numeric coercion, blank-field handling, parameter mapping, boolean preservation, and output declarations.

Reviews (3): Last reviewed commit: "fix(okta): make the params transform aut..." | Re-trigger Greptile

Comment thread apps/sim/blocks/blocks/okta.ts Outdated
The block covered user and group CRUD only, which left out the operations a
service desk and a SecOps team actually run. Adds 26 tools across the six
areas IT buyers ask for:

- System Log: query sign-ins and admin changes over a time window
- Factors: list, get, enroll, reset one, and reset all MFA factors
- Sessions: get, revoke one, and clear every session for a user
- Applications: list and get apps, and review or change user and group
  assignments
- Roles: list, assign, and revoke admin roles
- Group rules: list, get, create, activate, deactivate, and delete

Every endpoint and response shape was verified against the Okta Management
API reference. Three corrections the docs forced over the obvious guess: a
single factor is unenrolled with DELETE, not a lifecycle/reset that does not
exist; reset_factors takes no query parameters, so removeRecoveryEnrollment
belongs only to the single-factor DELETE; and group rule people conditions
carry exclude lists only, with no include counterpart.

Okta paginates with an opaque cursor advertised in the Link header rather
than a body field, which nothing here handled before. parseOktaPagination
reads it once and the list tools surface nextCursor and hasMore, so a caller
can page without reconstructing a URL. oktaHeaders and throwOktaError pull
the repeated SSWS auth and errorSummary unwrapping out of every new tool.
…ng them polymorphic

Okta types ApplicationVisibility and ApplicationAccessibility on the base
Application schema, so their fields are the same for every app - unlike
settings, which is redeclared per app kind, and profile, which accepts any
JSON schema. Calling all four "varies by application" was wrong for the two
that don't, so the fixed pair now names its fields and the genuinely
polymorphic pair says why it varies.

Also corrects includeNonDeleted, which returns inactive apps rather than
non-deleted ones, and only shows the custom-role fields once the role type
is CUSTOM, since they are meaningless for a standard role.

Reverts unrelated docs drift the generator swept in from the base branch.
Both fields are free-text inputs coerced with Number(), so a stray
non-numeric entry became NaN and serialized to null, which Okta rejects
with a validation error pointing at the wrong field. Omit the field
instead so Okta applies its own default.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

parseOktaPagination is the load-bearing piece of the pagination retrofit —
Okta advertises the opaque after cursor only in a Link header, never in the
body — so pin the next/self/absent/malformed cases along with the group-rule
mapper's exclude-only conditions and absent-nesting defaults.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2d3b68b. Configure here.

…d inputs

The generic block handler merges the transform on top of the raw serialized
inputs (`{ ...inputs, ...transformedParams }`), so a key the transform omits
keeps the raw subBlock string rather than being dropped. Two intended
behaviors were silently defeated by that merge:

- a non-numeric `limit` or `priority` reached Okta verbatim instead of being
  dropped so Okta could apply its own default
- a blank profile field in `update_user` — a POST merge, so a partial update —
  overwrote the stored Okta value with an empty string instead of leaving it
  untouched

Assign every key the block can send, including the ones it drops, so
`undefined` actually removes them. Cover both cases with tests that assert on
the merge rather than on the transform alone.

Also align the block with what the tools really return: drop `targets` and
`debugData`, which only exist nested inside a System Log event and were never
emitted at the top level, and surface the fifteen user and group profile
fields `get_user` and `get_group` emit but the block did not declare.

Declare `authMode` explicitly rather than leaning on the docs generator's
credential-subBlock heuristic, route the remaining fifteen tools through the
shared `oktaHeaders`/`throwOktaError` helpers so there is one auth and error
path, add wand prompts for the search, filter, expression, and timestamp
fields, and add skills for MFA reset, sign-in investigation, and application
access review to match the operations this block now has.

`limit` on List Group Members is Okta's default of 1000, not a maximum.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit cc1976b. Configure here.

@waleedlatif1
waleedlatif1 merged commit d45dad7 into staging Aug 15, 2026
29 of 30 checks passed
@waleedlatif1
waleedlatif1 deleted the feat/okta-depth branch August 15, 2026 23:47
waleedlatif1 added a commit that referenced this pull request Aug 16, 2026
* fix(okta): stop partial updates erasing stored profile data

Post-merge audit of the Okta integration (follows #6741), verified against the
OpenAPI spec bundled in okta-sdk-golang/.generator.

Two updates could silently destroy data:

- `update_group` targets `PUT /api/v1/groups/{groupId}`, which Okta documents as
  `replaceGroup` — it swaps the profile wholesale. Sending only the two fields
  the tool exposes erased the stored description on every rename, and dropped
  every org-defined custom attribute along with it. The tool now reads the group
  and overlays the supplied fields before replacing, matching the read-modify-
  write `salesforce_update_custom_field` already uses for the same hazard.
- `update_user` gated its profile fields on `!== undefined`, so an empty string
  reached Okta and blanked the stored value. The block strips blanks before they
  get there, but the tool is `user-or-llm` and a model routinely emits `""` for a
  field it has nothing to say about, so the guard belongs on the tool.

Also corrected:

- `forgetDevices` defaults to true at Okta, so the unseeded switch rendered off
  while remembered factors were in fact being cleared.
- Group rules take a plain keyword on `search`, not the SCIM-style expression the
  shared Search field's wand generates, so they get their own field.
- `get_logs` dropped `limit=0`, which the spec documents as valid.
- `get_user` emitted an activation timestamp under `activated`, which the block
  declares as the lifecycle boolean; the timestamp is now `activatedAt`.
- Descriptions that overstated what an endpoint does: `list_users` omits
  DEPROVISIONED users, `delete_user` deactivates before it deletes,
  `delete_group_rule` answers 202, and `excludedGroupIds` is always empty because
  Okta does not support group exclusions.

* fix(okta): forward the abort signal through the group read-modify-write

* test(okta): rename the shared body-builder helper

* fix(okta): key the send-email and search mappings off the operation

* docs(okta): use TSDoc for the new block annotations
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant