@arbium/enterprise-agent-connect 0.1.1 → 0.1.2-dev.cba5f68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +164 -12
  2. package/dist/connectors/dell-techdirect/index.d.ts +8 -0
  3. package/dist/connectors/dell-techdirect/tools.d.ts +2 -0
  4. package/dist/connectors/dell-techdirect/vendor.d.ts +6 -0
  5. package/dist/connectors/dynamics-365/connector.json +228 -0
  6. package/dist/connectors/dynamics-365/index.d.ts +8 -0
  7. package/dist/connectors/dynamics-365/index.js +10 -0
  8. package/dist/connectors/dynamics-365/index.js.map +1 -0
  9. package/dist/connectors/dynamics-365/tools.d.ts +35 -0
  10. package/dist/connectors/dynamics-365/tools.js +806 -0
  11. package/dist/connectors/dynamics-365/tools.js.map +1 -0
  12. package/dist/connectors/dynamics-365/vendor.d.ts +9 -0
  13. package/dist/connectors/dynamics-365/vendor.js +110 -0
  14. package/dist/connectors/dynamics-365/vendor.js.map +1 -0
  15. package/dist/connectors/entra/index.d.ts +2 -0
  16. package/dist/connectors/entra/tools.d.ts +14 -0
  17. package/dist/connectors/fedex/index.d.ts +8 -0
  18. package/dist/connectors/fedex/tools.d.ts +3 -0
  19. package/dist/connectors/fedex/vendor.d.ts +7 -0
  20. package/dist/connectors/gong/connector.json +127 -0
  21. package/dist/connectors/gong/index.d.ts +8 -0
  22. package/dist/connectors/gong/index.js +7 -0
  23. package/dist/connectors/gong/index.js.map +1 -0
  24. package/dist/connectors/gong/tools.d.ts +8 -0
  25. package/dist/connectors/gong/tools.js +424 -0
  26. package/dist/connectors/gong/tools.js.map +1 -0
  27. package/dist/connectors/gong/vendor.d.ts +4 -0
  28. package/dist/connectors/gong/vendor.js +89 -0
  29. package/dist/connectors/gong/vendor.js.map +1 -0
  30. package/dist/connectors/http/index.d.ts +34 -0
  31. package/dist/connectors/http/index.js +154 -64
  32. package/dist/connectors/http/index.js.map +1 -1
  33. package/dist/connectors/intune/index.d.ts +2 -0
  34. package/dist/connectors/intune/tools.d.ts +12 -0
  35. package/dist/connectors/jamf/connector.json +182 -0
  36. package/dist/connectors/jamf/index.d.ts +8 -0
  37. package/dist/connectors/jamf/index.js +7 -0
  38. package/dist/connectors/jamf/index.js.map +1 -0
  39. package/dist/connectors/jamf/tools.d.ts +7 -0
  40. package/dist/connectors/jamf/tools.js +659 -0
  41. package/dist/connectors/jamf/tools.js.map +1 -0
  42. package/dist/connectors/jamf/vendor.d.ts +5 -0
  43. package/dist/connectors/jamf/vendor.js +70 -0
  44. package/dist/connectors/jamf/vendor.js.map +1 -0
  45. package/dist/connectors/jira/connector.json +144 -1
  46. package/dist/connectors/jira/index.d.ts +8 -0
  47. package/dist/connectors/jira/jql.d.ts +4 -0
  48. package/dist/connectors/jira/tools.d.ts +3 -0
  49. package/dist/connectors/jira/vendor.d.ts +3 -0
  50. package/dist/connectors/jira/vendor.js +8 -2
  51. package/dist/connectors/jira/vendor.js.map +1 -1
  52. package/dist/connectors/microsoft/client.d.ts +66 -0
  53. package/dist/connectors/microsoft/client.js +26 -8
  54. package/dist/connectors/microsoft/client.js.map +1 -1
  55. package/dist/connectors/netsuite/connector.json +317 -0
  56. package/dist/connectors/netsuite/index.d.ts +8 -0
  57. package/dist/connectors/netsuite/index.js +7 -0
  58. package/dist/connectors/netsuite/index.js.map +1 -0
  59. package/dist/connectors/netsuite/tools.d.ts +24 -0
  60. package/dist/connectors/netsuite/tools.js +447 -0
  61. package/dist/connectors/netsuite/tools.js.map +1 -0
  62. package/dist/connectors/netsuite/vendor.d.ts +26 -0
  63. package/dist/connectors/netsuite/vendor.js +247 -0
  64. package/dist/connectors/netsuite/vendor.js.map +1 -0
  65. package/dist/connectors/odata/index.d.ts +33 -0
  66. package/dist/connectors/odata/index.js +460 -0
  67. package/dist/connectors/odata/index.js.map +1 -0
  68. package/dist/connectors/okta/connector.json +194 -0
  69. package/dist/connectors/okta/index.d.ts +8 -0
  70. package/dist/connectors/okta/index.js +7 -0
  71. package/dist/connectors/okta/index.js.map +1 -0
  72. package/dist/connectors/okta/tools.d.ts +6 -0
  73. package/dist/connectors/okta/tools.js +429 -0
  74. package/dist/connectors/okta/tools.js.map +1 -0
  75. package/dist/connectors/okta/vendor.d.ts +14 -0
  76. package/dist/connectors/okta/vendor.js +204 -0
  77. package/dist/connectors/okta/vendor.js.map +1 -0
  78. package/dist/connectors/outlook-calendar/index.d.ts +2 -0
  79. package/dist/connectors/outlook-calendar/tools.d.ts +65 -0
  80. package/dist/connectors/outlook-mail/index.d.ts +2 -0
  81. package/dist/connectors/outlook-mail/tools.d.ts +8 -0
  82. package/dist/connectors/salesforce/index.d.ts +8 -0
  83. package/dist/connectors/salesforce/soql.d.ts +3 -0
  84. package/dist/connectors/salesforce/tools.d.ts +9 -0
  85. package/dist/connectors/salesforce/vendor.d.ts +3 -0
  86. package/dist/connectors/salesforce/vendor.js +9 -3
  87. package/dist/connectors/salesforce/vendor.js.map +1 -1
  88. package/dist/connectors/sap-s4hana/connector.json +264 -0
  89. package/dist/connectors/sap-s4hana/index.d.ts +8 -0
  90. package/dist/connectors/sap-s4hana/index.js +7 -0
  91. package/dist/connectors/sap-s4hana/index.js.map +1 -0
  92. package/dist/connectors/sap-s4hana/tools.d.ts +4 -0
  93. package/dist/connectors/sap-s4hana/tools.js +761 -0
  94. package/dist/connectors/sap-s4hana/tools.js.map +1 -0
  95. package/dist/connectors/sap-s4hana/vendor.d.ts +5 -0
  96. package/dist/connectors/sap-s4hana/vendor.js +176 -0
  97. package/dist/connectors/sap-s4hana/vendor.js.map +1 -0
  98. package/dist/connectors/servicenow/connector.json +228 -0
  99. package/dist/connectors/servicenow/index.d.ts +8 -0
  100. package/dist/connectors/servicenow/index.js +7 -0
  101. package/dist/connectors/servicenow/index.js.map +1 -0
  102. package/dist/connectors/servicenow/tools.d.ts +4 -0
  103. package/dist/connectors/servicenow/tools.js +884 -0
  104. package/dist/connectors/servicenow/tools.js.map +1 -0
  105. package/dist/connectors/servicenow/vendor.d.ts +3 -0
  106. package/dist/connectors/servicenow/vendor.js +106 -0
  107. package/dist/connectors/servicenow/vendor.js.map +1 -0
  108. package/dist/connectors/sharepoint-files/excel.d.ts +16 -0
  109. package/dist/connectors/sharepoint-files/index.d.ts +8 -0
  110. package/dist/connectors/sharepoint-files/index.js.map +1 -1
  111. package/dist/connectors/sharepoint-files/tools.d.ts +52 -0
  112. package/dist/connectors/sharepoint-files/vendor.d.ts +11 -0
  113. package/dist/connectors/slack/connector.json +148 -0
  114. package/dist/connectors/slack/index.d.ts +8 -0
  115. package/dist/connectors/slack/index.js +7 -0
  116. package/dist/connectors/slack/index.js.map +1 -0
  117. package/dist/connectors/slack/tools.d.ts +3 -0
  118. package/dist/connectors/slack/tools.js +355 -0
  119. package/dist/connectors/slack/tools.js.map +1 -0
  120. package/dist/connectors/slack/vendor.d.ts +17 -0
  121. package/dist/connectors/slack/vendor.js +189 -0
  122. package/dist/connectors/slack/vendor.js.map +1 -0
  123. package/dist/connectors/soap/index.d.ts +16 -0
  124. package/dist/connectors/soap/index.js +248 -0
  125. package/dist/connectors/soap/index.js.map +1 -0
  126. package/dist/connectors/soap/xml.d.ts +12 -0
  127. package/dist/connectors/soap/xml.js +126 -0
  128. package/dist/connectors/soap/xml.js.map +1 -0
  129. package/dist/connectors/sql/engines.d.ts +58 -0
  130. package/dist/connectors/sql/engines.js +292 -0
  131. package/dist/connectors/sql/engines.js.map +1 -0
  132. package/dist/connectors/sql/index.d.ts +16 -0
  133. package/dist/connectors/sql/index.js +214 -0
  134. package/dist/connectors/sql/index.js.map +1 -0
  135. package/dist/connectors/teams/index.d.ts +2 -0
  136. package/dist/connectors/teams/tools.d.ts +7 -0
  137. package/dist/connectors/teams/tools.js +3 -2
  138. package/dist/connectors/teams/tools.js.map +1 -1
  139. package/dist/connectors/workday/connector.json +188 -0
  140. package/dist/connectors/workday/index.d.ts +8 -0
  141. package/dist/connectors/workday/index.js +7 -0
  142. package/dist/connectors/workday/index.js.map +1 -0
  143. package/dist/connectors/workday/tools.d.ts +33 -0
  144. package/dist/connectors/workday/tools.js +410 -0
  145. package/dist/connectors/workday/tools.js.map +1 -0
  146. package/dist/connectors/workday/vendor.d.ts +18 -0
  147. package/dist/connectors/workday/vendor.js +199 -0
  148. package/dist/connectors/workday/vendor.js.map +1 -0
  149. package/dist/packages/connector-kit/src/branding.d.ts +57 -0
  150. package/dist/packages/connector-kit/src/certificate.d.ts +19 -0
  151. package/dist/packages/connector-kit/src/common.d.ts +36 -0
  152. package/dist/packages/connector-kit/src/common.js +4 -1
  153. package/dist/packages/connector-kit/src/common.js.map +1 -1
  154. package/dist/packages/connector-kit/src/connector.d.ts +1356 -0
  155. package/dist/packages/connector-kit/src/connector.js +632 -53
  156. package/dist/packages/connector-kit/src/connector.js.map +1 -1
  157. package/dist/packages/connector-kit/src/fetch.d.ts +6 -0
  158. package/dist/packages/connector-kit/src/fetch.js +44 -0
  159. package/dist/packages/connector-kit/src/fetch.js.map +1 -0
  160. package/dist/packages/connector-kit/src/index.d.ts +5 -0
  161. package/dist/packages/connector-kit/src/index.js +6 -0
  162. package/dist/packages/connector-kit/src/index.js.map +1 -0
  163. package/dist/packages/connector-kit/src/oauth.d.ts +15 -0
  164. package/dist/packages/connector-kit/src/oauth.js +25 -6
  165. package/dist/packages/connector-kit/src/oauth.js.map +1 -1
  166. package/dist/packages/connector-kit/src/types.d.ts +87 -0
  167. package/dist/packages/connector-kit/src/types.js.map +1 -1
  168. package/dist/packages/server/migrations/0007_app_events.sql +110 -0
  169. package/dist/packages/server/migrations/rollback/to-legacy.sql +3 -0
  170. package/dist/packages/server/src/api.d.ts +3730 -0
  171. package/dist/packages/server/src/api.js +137 -1
  172. package/dist/packages/server/src/api.js.map +1 -1
  173. package/dist/packages/server/src/app.d.ts +23 -0
  174. package/dist/packages/server/src/app.js +24 -1
  175. package/dist/packages/server/src/app.js.map +1 -1
  176. package/dist/packages/server/src/builtin.d.ts +5 -0
  177. package/dist/packages/server/src/builtin.js +18 -0
  178. package/dist/packages/server/src/builtin.js.map +1 -1
  179. package/dist/packages/server/src/consent.d.ts +27 -0
  180. package/dist/packages/server/src/events/admin.d.ts +156 -0
  181. package/dist/packages/server/src/events/admin.js +255 -0
  182. package/dist/packages/server/src/events/admin.js.map +1 -0
  183. package/dist/packages/server/src/events/deliver.d.ts +43 -0
  184. package/dist/packages/server/src/events/deliver.js +129 -0
  185. package/dist/packages/server/src/events/deliver.js.map +1 -0
  186. package/dist/packages/server/src/events/runtime.d.ts +28 -0
  187. package/dist/packages/server/src/events/runtime.js +397 -0
  188. package/dist/packages/server/src/events/runtime.js.map +1 -0
  189. package/dist/packages/server/src/events/store.d.ts +172 -0
  190. package/dist/packages/server/src/events/store.js +275 -0
  191. package/dist/packages/server/src/events/store.js.map +1 -0
  192. package/dist/packages/server/src/index.d.ts +40 -0
  193. package/dist/packages/server/src/index.js +68 -11
  194. package/dist/packages/server/src/index.js.map +1 -1
  195. package/dist/packages/server/src/migrate.d.ts +11 -0
  196. package/dist/packages/server/src/openapi.d.ts +4 -0
  197. package/dist/packages/server/src/openapi.js +2 -2
  198. package/dist/packages/server/src/openapi.js.map +1 -1
  199. package/dist/packages/server/src/queue.d.ts +10 -0
  200. package/dist/packages/server/src/queue.js +45 -0
  201. package/dist/packages/server/src/queue.js.map +1 -0
  202. package/dist/packages/server/src/secrets.d.ts +19 -0
  203. package/dist/packages/server/src/server.d.ts +1 -0
  204. package/dist/packages/server/src/server.js +14 -1
  205. package/dist/packages/server/src/server.js.map +1 -1
  206. package/dist/packages/server/src/service.d.ts +767 -0
  207. package/dist/packages/server/src/service.js +19 -3
  208. package/dist/packages/server/src/service.js.map +1 -1
  209. package/dist/packages/server/src/store.d.ts +157 -0
  210. package/dist/packages/server/src/store.js +4 -0
  211. package/dist/packages/server/src/store.js.map +1 -1
  212. package/dist/packages/server/src/teams/activity.d.ts +123 -0
  213. package/dist/packages/server/src/teams/activity.js +6 -5
  214. package/dist/packages/server/src/teams/activity.js.map +1 -1
  215. package/dist/packages/server/src/teams/admin.d.ts +335 -0
  216. package/dist/packages/server/src/teams/admin.js +1 -1
  217. package/dist/packages/server/src/teams/admin.js.map +1 -1
  218. package/dist/packages/server/src/teams/approval.d.ts +57 -0
  219. package/dist/packages/server/src/teams/bot.d.ts +25 -0
  220. package/dist/packages/server/src/teams/claude.d.ts +46 -0
  221. package/dist/packages/server/src/teams/jwt.d.ts +17 -0
  222. package/dist/packages/server/src/teams/package.d.ts +79 -0
  223. package/dist/packages/server/src/teams/provision.d.ts +84 -0
  224. package/dist/packages/server/src/teams/runner.d.ts +80 -0
  225. package/dist/packages/server/src/teams/runner.js +50 -6
  226. package/dist/packages/server/src/teams/runner.js.map +1 -1
  227. package/dist/packages/server/src/teams/runtime.d.ts +91 -0
  228. package/dist/packages/server/src/teams/runtime.js +25 -47
  229. package/dist/packages/server/src/teams/runtime.js.map +1 -1
  230. package/dist/packages/server/src/teams/store.d.ts +233 -0
  231. package/package.json +28 -2
@@ -0,0 +1,194 @@
1
+ {
2
+ "id": "okta",
3
+ "name": "Okta",
4
+ "description": "Let agents look up people, groups, apps and sign-in activity in Okta and, if you allow it, help people back in: unlock accounts, send password reset emails, reset MFA, change group membership, suspend or deactivate.",
5
+ "logo": "/brand/registry/okta.svg",
6
+ "identity": "An Okta API service app named \"{brand.microsoft.appName}\". It signs in with a key pair, has only the Okta API scopes you grant it, and can act only within the admin role you assign it. Each API key can be kept to the members of chosen groups.",
7
+ "accountKey": "org",
8
+ "connectionKind": "guided",
9
+ "setup": [
10
+ {
11
+ "title": "Create an API service app",
12
+ "body": "In the Okta Admin Console, create an API Services app named \"{brand.microsoft.appName}\". You need a Super Administrator for this and the steps below. Keep its Client ID for the form below.",
13
+ "link": {
14
+ "label": "Okta: service app for the Okta API",
15
+ "href": "https://developer.okta.com/docs/guides/implement-oauth-for-okta-serviceapp/main/"
16
+ },
17
+ "click": [
18
+ "In the Okta Admin Console, go to Applications, then Applications, and select Create App Integration.",
19
+ "Choose API Services and select Next.",
20
+ "Name it {brand.microsoft.appName} and select Save.",
21
+ "On the General tab, copy the Client ID."
22
+ ]
23
+ },
24
+ {
25
+ "title": "Give it a key pair",
26
+ "body": "The app signs in with a private key instead of a secret. Okta generates the key and shows the private key only once. Clear the proof-of-possession (DPoP) requirement: the app does not send it.",
27
+ "click": [
28
+ "On the app's General tab, under Client Credentials, select Edit.",
29
+ "For Client authentication choose Public key / Private key, and clear Require Demonstrating Proof of Possession (DPoP) header in token requests.",
30
+ "Under Public keys select Add key, then Generate new key. Copy the private key (PEM), then select Done.",
31
+ "Select Save. Copy the KID shown beside the key."
32
+ ]
33
+ },
34
+ {
35
+ "title": "Grant these Okta API scopes",
36
+ "body": "On the app's Okta API Scopes tab, grant exactly these and nothing else. The app can do nothing a scope does not cover. With Commands, use an Okta API token of a Super Administrator (Security, then API, then Tokens) and the app's Client ID.",
37
+ "click": [
38
+ "Open the app's Okta API Scopes tab.",
39
+ "Select Grant beside each of {scopes}."
40
+ ],
41
+ "copy": [
42
+ "OKTA=https://your-company.okta.com",
43
+ "CLIENT_ID=the-client-id",
44
+ "curl -s -X POST \"$OKTA/api/v1/apps/$CLIENT_ID/grants\" -H \"Authorization: SSWS $OKTA_API_TOKEN\" -H \"Content-Type: application/json\" -d \"{\\\"scopeId\\\": \\\"{scope}\\\", \\\"issuer\\\": \\\"$OKTA\\\"}\""
45
+ ],
46
+ "shell": "bash"
47
+ },
48
+ {
49
+ "title": "Assign it an admin role",
50
+ "body": "Okta also checks the app's admin role on every call, so a scope alone is not enough. Create a custom admin role with the permissions below and a resource set holding the groups agents may work with, then assign both to the app. Okta then refuses anything outside them, whatever an agent asks.",
51
+ "permissions": true,
52
+ "click": [
53
+ "Go to Security, then Administrators, then Roles, and select Create new role. Name it {brand.microsoft.appName}, tick the permissions below and select Save role.",
54
+ "Under Resources, select Create new resource set, add the groups agents may work with, and save it.",
55
+ "Open the app's Admin roles tab and select Edit assignments, then Add assignment.",
56
+ "Choose the role and the resource set you made, and select Save changes."
57
+ ]
58
+ }
59
+ ],
60
+ "afterConnect": [],
61
+ "fields": [
62
+ {
63
+ "id": "org",
64
+ "label": "Okta address",
65
+ "help": "Your Okta organization's address, without -admin.",
66
+ "placeholder": "your-company.okta.com",
67
+ "secret": false
68
+ },
69
+ {
70
+ "id": "client_id",
71
+ "label": "Client ID",
72
+ "help": "On the app's General tab.",
73
+ "secret": false
74
+ },
75
+ {
76
+ "id": "key_id",
77
+ "label": "Key ID (KID)",
78
+ "help": "Shown beside the key under Public keys. Needed only when the app has more than one key.",
79
+ "secret": false,
80
+ "optional": true
81
+ },
82
+ {
83
+ "id": "private_key",
84
+ "label": "Private key",
85
+ "help": "The private key Okta showed when it generated the key, PEM or JSON.",
86
+ "secret": true
87
+ }
88
+ ],
89
+ "capabilities": [
90
+ {
91
+ "id": "read",
92
+ "label": "Look up people and groups",
93
+ "description": "Find people and read their username, email, title, department, account status, last sign-in, groups and enrolled MFA factors. Find groups and list their members.",
94
+ "required": true,
95
+ "note": "Reaches everyone in your Okta organization unless you keep a key to chosen groups under API keys. Read-only.",
96
+ "scopes": ["okta.users.read", "okta.groups.read"],
97
+ "permissions": ["View users and their details", "View groups and their details"],
98
+ "tools": [
99
+ "okta_get_user",
100
+ "okta_search_users",
101
+ "okta_list_factors",
102
+ "okta_search_groups",
103
+ "okta_list_group_members"
104
+ ],
105
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it (the Okta page in {brand.productName} shows how)."
106
+ },
107
+ {
108
+ "id": "read_apps",
109
+ "label": "Look up apps",
110
+ "description": "List the apps in Okta and the apps assigned to a person.",
111
+ "scopes": ["okta.apps.read"],
112
+ "permissions": ["View applications and their details"],
113
+ "tools": ["okta_list_apps"],
114
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
115
+ },
116
+ {
117
+ "id": "read_activity",
118
+ "label": "Read sign-in activity",
119
+ "description": "Read a person's recent sign-ins, MFA challenges, lockouts and account changes from the System Log, with IP address, place and browser.",
120
+ "scopes": ["okta.logs.read"],
121
+ "permissions": ["View the System Log"],
122
+ "tools": ["okta_get_user_activity"],
123
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
124
+ },
125
+ {
126
+ "id": "manage_groups",
127
+ "label": "Change group membership",
128
+ "description": "Add people to groups and remove them. Membership can give people apps and access.",
129
+ "note": "With a key kept to chosen groups, agents can only add or remove those groups' members, and only to and from those groups.",
130
+ "scopes": ["okta.groups.manage"],
131
+ "permissions": ["Manage group membership"],
132
+ "tools": ["okta_add_group_member", "okta_remove_group_member"],
133
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
134
+ },
135
+ {
136
+ "id": "helpdesk",
137
+ "label": "Unlock accounts and send password resets",
138
+ "description": "Unlock people who are locked out, and email people a link to set a new password.",
139
+ "scopes": ["okta.users.manage"],
140
+ "permissions": ["Unlock users", "Reset users' passwords"],
141
+ "tools": ["okta_unlock_user", "okta_send_password_reset"],
142
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
143
+ },
144
+ {
145
+ "id": "reset_mfa",
146
+ "label": "Reset MFA",
147
+ "description": "Remove a person's enrolled MFA factor, e.g. after a lost phone. They set it up again at their next sign-in.",
148
+ "destructive": true,
149
+ "note": "Until they set it up again, the person signs in without that factor. Okta cannot bring a removed factor back.",
150
+ "scopes": ["okta.users.manage"],
151
+ "permissions": ["Reset users' authenticators"],
152
+ "tools": ["okta_reset_factor"],
153
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
154
+ },
155
+ {
156
+ "id": "suspend",
157
+ "label": "Suspend people and sign them out",
158
+ "description": "Suspend and unsuspend people, and sign people out of every session.",
159
+ "destructive": true,
160
+ "note": "A suspended or signed-out person cannot work until someone lets them back in.",
161
+ "scopes": ["okta.users.manage"],
162
+ "permissions": ["Suspend users", "Unsuspend users", "Clear users' sessions"],
163
+ "tools": ["okta_suspend_user", "okta_unsuspend_user", "okta_clear_sessions"],
164
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
165
+ },
166
+ {
167
+ "id": "deactivate",
168
+ "label": "Deactivate people",
169
+ "description": "Deactivate people: they can no longer sign in, and apps set up for it remove their accounts.",
170
+ "destructive": true,
171
+ "note": "Deactivating can remove a person's accounts in other apps. Only an administrator can reactivate them, and removed app accounts may not come back.",
172
+ "scopes": ["okta.users.manage"],
173
+ "permissions": ["Deactivate users"],
174
+ "tools": ["okta_deactivate_user"],
175
+ "forbidden": "Okta refused this. The app needs {scopes} granted and an admin role that allows it."
176
+ }
177
+ ],
178
+ "limits": [
179
+ {
180
+ "id": "groups",
181
+ "label": "Groups",
182
+ "help": "Optional: only people in these groups (their ids, 00g..., from the group's address in the Okta Admin Console), and only these groups. Leave empty for everyone.",
183
+ "kind": "list",
184
+ "required": false,
185
+ "pattern": "^00g[A-Za-z0-9]{17}$"
186
+ }
187
+ ],
188
+ "verify": {
189
+ "label": "Okta API scopes the app has",
190
+ "check": "scopes",
191
+ "ifEmpty": "The app has none of the Okta API scopes needed yet. Grant them on its Okta API Scopes tab."
192
+ },
193
+ "revoke": "In the Okta Admin Console, open Applications, then {brand.microsoft.appName}, and deactivate it, or remove its key or its Okta API scopes. Agents lose access to Okta at once."
194
+ }
@@ -0,0 +1,8 @@
1
+ declare const _default: {
2
+ id: string;
3
+ create: () => {
4
+ vendor: import("../../packages/connector-kit/src/types.js").Vendor;
5
+ toolset: import("../../packages/connector-kit/src/common.js").Toolset;
6
+ };
7
+ };
8
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import { oktaTools } from "./tools.js";
2
+ import { oktaVendor } from "./vendor.js";
3
+ export default {
4
+ id: "okta",
5
+ create: () => ({ vendor: oktaVendor(), toolset: oktaTools }),
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../connectors/okta/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAe;IACb,EAAE,EAAE,MAAM;IACV,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;CACnC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type ToolContext, type Toolset } from "../../packages/connector-kit/src/common.js";
2
+ export declare const MAX_GROUP_PAGES = 5;
3
+ export declare const MAX_SCOPED_PAGES = 5;
4
+ /** The key's group ids; null when it has none. */
5
+ export declare function groupScope(ctx: ToolContext): Set<string> | null;
6
+ export declare const oktaTools: Toolset;
@@ -0,0 +1,429 @@
1
+ import { z } from "zod";
2
+ import { audited, Denied, json, listLimit, VendorFailed, } from "../../packages/connector-kit/src/common.js";
3
+ import { cursorArg } from "../sharepoint-files/tools.js";
4
+ // People, groups, apps and sign-in activity in Okta, and the help desk's actions on a person.
5
+ // A key's `groups` limit (Okta group ids) keeps it to the members of those groups: every tool
6
+ // that names a person reads the person's groups first, and every write checks before it calls.
7
+ // Okta has no nested groups, so membership is direct. Request shapes: developer.okta.com/docs/
8
+ // api/openapi/okta-management/management/tag/User, UserLifecycle, UserSessions, UserFactor,
9
+ // Group, Application and SystemLog (read October 27, 2026).
10
+ const USER_ID = /^00u[A-Za-z0-9]{17}$/;
11
+ const GROUP_ID = /^00g[A-Za-z0-9]{17}$/;
12
+ const FACTOR_ID = /^[A-Za-z0-9]{20}$/;
13
+ const LOGIN = /^[^\s/\\?#%"]{1,100}$/;
14
+ const EVENT_TYPE = /^[a-z0-9_.]{1,100}$/;
15
+ const STATUSES = [
16
+ "ACTIVE",
17
+ "LOCKED_OUT",
18
+ "PASSWORD_EXPIRED",
19
+ "RECOVERY",
20
+ "SUSPENDED",
21
+ "PROVISIONED",
22
+ "STAGED",
23
+ "DEPROVISIONED",
24
+ ];
25
+ // A person's groups are read at most this many pages of 200 for the limit check; past it the
26
+ // person reads as outside the key's groups (refused, never widened).
27
+ export const MAX_GROUP_PAGES = 5;
28
+ // Under a groups limit a search reads on, at most this many pages, until it has `max_results`.
29
+ export const MAX_SCOPED_PAGES = 5;
30
+ // Okta keeps the System Log 90 days.
31
+ const MAX_HOURS = 90 * 24;
32
+ function oktaError(res) {
33
+ const d = res.data;
34
+ const detail = [d?.errorSummary, ...(d?.errorCauses ?? []).map((c) => c.errorSummary)]
35
+ .filter(Boolean)
36
+ .join("; ");
37
+ return new VendorFailed(res.status, `Okta answered ${res.status}${detail ? `: ${detail}` : ""}`);
38
+ }
39
+ async function ok(ctx, mark, req) {
40
+ const res = await ctx.call(req);
41
+ mark(res.status);
42
+ if (res.status < 200 || res.status >= 300)
43
+ throw oktaError(res);
44
+ return res.data;
45
+ }
46
+ const page = (ctx, mark, path) => ok(ctx, mark, { method: "GET", path });
47
+ const after = (cursor) => cursor ? `&after=${encodeURIComponent(cursor)}` : "";
48
+ /** The key's group ids; null when it has none. */
49
+ export function groupScope(ctx) {
50
+ const groups = listLimit(ctx.limits, "groups");
51
+ return groups ? new Set(groups) : null;
52
+ }
53
+ async function groupsOf(ctx, mark, userId) {
54
+ const groups = [];
55
+ let cursor = null;
56
+ for (let read = 0; read < MAX_GROUP_PAGES; read++) {
57
+ const data = await page(ctx, mark, `/api/v1/users/${userId}/groups?limit=200${after(cursor)}`);
58
+ groups.push(...data.items);
59
+ cursor = data.after;
60
+ if (!cursor)
61
+ break;
62
+ }
63
+ return groups;
64
+ }
65
+ const inScope = (scope, groups) => !scope || groups.some((g) => scope.has(g.id));
66
+ function userRef(raw) {
67
+ const value = raw.trim();
68
+ if (!USER_ID.test(value) && !LOGIN.test(value))
69
+ throw new Denied("Give a person's Okta id or username, such as ada@acme.com");
70
+ return encodeURIComponent(value);
71
+ }
72
+ /** The person, read and checked against the key's groups; `groups` only when read. */
73
+ async function openUser(ctx, mark, raw, withGroups = false) {
74
+ const scope = groupScope(ctx);
75
+ const denied = new Denied("This agent may not look up or act on that person");
76
+ let user;
77
+ try {
78
+ user = await ok(ctx, mark, { method: "GET", path: `/api/v1/users/${userRef(raw)}` });
79
+ }
80
+ catch (error) {
81
+ // A kept key must not learn which usernames exist outside its groups.
82
+ if (scope && error instanceof VendorFailed && error.status === 404)
83
+ throw denied;
84
+ throw error;
85
+ }
86
+ if (!USER_ID.test(user.id ?? ""))
87
+ throw new Error("Okta answered a user without an id");
88
+ const groups = scope || withGroups ? await groupsOf(ctx, mark, user.id) : [];
89
+ if (!inScope(scope, groups))
90
+ throw denied;
91
+ return { user, groups, scope };
92
+ }
93
+ const person = (u) => ({
94
+ id: u.id,
95
+ login: u.profile?.login ?? null,
96
+ email: u.profile?.email ?? null,
97
+ name: [u.profile?.firstName, u.profile?.lastName].filter(Boolean).join(" ") || null,
98
+ title: u.profile?.title ?? null,
99
+ department: u.profile?.department ?? null,
100
+ status: u.status ?? null,
101
+ });
102
+ const group = (g) => ({
103
+ id: g.id,
104
+ name: g.profile?.name ?? null,
105
+ description: g.profile?.description ?? null,
106
+ type: g.type ?? null,
107
+ });
108
+ /** A listing page kept to what `keep` allows; `next` continues after the last page read. */
109
+ async function keptPage(ctx, mark, path, max, cursor, scoped, keep) {
110
+ const kept = [];
111
+ let next = cursor ?? null;
112
+ for (let read = 0; read < (scoped ? MAX_SCOPED_PAGES : 1); read++) {
113
+ const data = await page(ctx, mark, path(after(next)));
114
+ for (const item of await Promise.all(data.items.map(keep)))
115
+ if (item !== null)
116
+ kept.push(item);
117
+ next = data.after;
118
+ if (!next || kept.length >= max)
119
+ break;
120
+ }
121
+ return { kept, more: Boolean(next), next };
122
+ }
123
+ // Search words go inside Okta's quoted filter strings.
124
+ const words = (raw) => raw.replace(/["\\]/g, "").trim();
125
+ // The log window rides in the cursor, so a later page reads the same window.
126
+ const ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;
127
+ function logWindow(cursor) {
128
+ if (!cursor)
129
+ return { until: new Date().toISOString(), after: null };
130
+ const split = cursor.indexOf("~");
131
+ const [until, rest] = [cursor.slice(0, split), cursor.slice(split + 1)];
132
+ if (split < 0 || !ISO.test(until) || !rest)
133
+ throw new Denied("Give `next` from the previous call as `cursor`");
134
+ return { until, after: rest };
135
+ }
136
+ function event(e, userId, scoped) {
137
+ const actor = e.actor ?? {};
138
+ const ua = e.client?.userAgent ?? {};
139
+ const geo = e.client?.geographicalContext ?? {};
140
+ const known = (v) => (typeof v === "string" && v && v !== "UNKNOWN" ? v : null);
141
+ return {
142
+ time: e.published ?? null,
143
+ event_type: e.eventType ?? null,
144
+ message: e.displayMessage ?? null,
145
+ outcome: e.outcome?.result ?? null,
146
+ reason: e.outcome?.reason ?? null,
147
+ // Under a groups limit another person's name could be outside the key's groups.
148
+ by: actor.id === userId
149
+ ? "this person"
150
+ : scoped && actor.type === "User"
151
+ ? "another person"
152
+ : (actor.displayName ?? null),
153
+ ip: e.client?.ipAddress ?? null,
154
+ location: [geo.city, geo.state, geo.country].filter(known).join(", ") || null,
155
+ client: [known(ua.browser), known(ua.os)].filter(Boolean).join(" on ") || null,
156
+ };
157
+ }
158
+ export const oktaTools = {
159
+ names: [
160
+ "okta_get_user",
161
+ "okta_search_users",
162
+ "okta_list_factors",
163
+ "okta_search_groups",
164
+ "okta_list_group_members",
165
+ "okta_list_apps",
166
+ "okta_get_user_activity",
167
+ "okta_add_group_member",
168
+ "okta_remove_group_member",
169
+ "okta_unlock_user",
170
+ "okta_send_password_reset",
171
+ "okta_reset_factor",
172
+ "okta_suspend_user",
173
+ "okta_unsuspend_user",
174
+ "okta_clear_sessions",
175
+ "okta_deactivate_user",
176
+ ],
177
+ register(server, ctx, allowed) {
178
+ const readOnly = { readOnlyHint: true, openWorldHint: true };
179
+ const write = (destructive) => ({ readOnlyHint: false, destructiveHint: destructive, openWorldHint: true });
180
+ const user = z
181
+ .string()
182
+ .max(100)
183
+ .describe("A person's Okta id (00u...) or username, such as ada@acme.com.");
184
+ const groupId = z.string().max(20).describe("A group's id (00g...), from okta_search_groups.");
185
+ const max = (most, fallback) => z.number().int().min(1).max(most).default(fallback);
186
+ const checkGroup = (scope, id) => {
187
+ if (!GROUP_ID.test(id))
188
+ throw new Denied("Give a group id from okta_search_groups");
189
+ if (scope && !scope.has(id))
190
+ throw new Denied("This agent may not use that group");
191
+ };
192
+ if (allowed.has("okta_get_user"))
193
+ server.registerTool("okta_get_user", {
194
+ description: "Look up one person: username, email, name, title, department, account status (ACTIVE, LOCKED_OUT, SUSPENDED, PASSWORD_EXPIRED, ...), last sign-in, last password change and their groups.",
195
+ inputSchema: z.object({ user }),
196
+ annotations: readOnly,
197
+ }, ({ user: u }) => audited(ctx, "okta_get_user", u, async (mark) => {
198
+ const { user: p, groups, scope } = await openUser(ctx, mark, u, true);
199
+ const shown = groups.filter((g) => !scope || scope.has(g.id));
200
+ return json({
201
+ ...person(p),
202
+ locked_out: p.status === "LOCKED_OUT",
203
+ last_login: p.lastLogin ?? null,
204
+ password_changed: p.passwordChanged ?? null,
205
+ status_changed: p.statusChanged ?? null,
206
+ created: p.created ?? null,
207
+ groups: shown.slice(0, 100).map(group),
208
+ more_groups: shown.length > 100,
209
+ });
210
+ }));
211
+ if (allowed.has("okta_search_users"))
212
+ server.registerTool("okta_search_users", {
213
+ description: "Find people whose username, email, first or last name starts with `query`, or everyone with a status (e.g. LOCKED_OUT). When `more` is true, call again with `cursor` set to `next`.",
214
+ inputSchema: z.object({
215
+ query: z.string().max(100).optional(),
216
+ status: z.enum(STATUSES).optional(),
217
+ max_results: max(50, 25),
218
+ cursor: cursorArg,
219
+ }),
220
+ annotations: readOnly,
221
+ }, ({ query, status, max_results, cursor }) => audited(ctx, "okta_search_users", query ?? status ?? null, async (mark) => {
222
+ const w = words(query ?? "");
223
+ if (!w && !status)
224
+ throw new Denied("Give a few letters of a name, or a status");
225
+ const parts = [
226
+ ...(w
227
+ ? [
228
+ `(${["login", "email", "firstName", "lastName"].map((f) => `profile.${f} sw "${w}"`).join(" or ")})`,
229
+ ]
230
+ : []),
231
+ ...(status ? [`status eq "${status}"`] : []),
232
+ ];
233
+ const search = encodeURIComponent(parts.join(" and "));
234
+ const scope = groupScope(ctx);
235
+ const { kept, more, next } = await keptPage(ctx, mark, (c) => `/api/v1/users?search=${search}&limit=${max_results}${c}`, max_results, cursor, Boolean(scope), async (u) => inScope(scope, scope ? await groupsOf(ctx, mark, u.id) : []) ? person(u) : null);
236
+ return json({ people: kept, more, next });
237
+ }));
238
+ if (allowed.has("okta_list_factors"))
239
+ server.registerTool("okta_list_factors", {
240
+ description: "List a person's enrolled MFA factors (authenticators): id, type, provider and status. Use an id with okta_reset_factor.",
241
+ inputSchema: z.object({ user }),
242
+ annotations: readOnly,
243
+ }, ({ user: u }) => audited(ctx, "okta_list_factors", u, async (mark) => {
244
+ const { user: p } = await openUser(ctx, mark, u);
245
+ const data = await page(ctx, mark, `/api/v1/users/${p.id}/factors`);
246
+ return json({
247
+ user: person(p),
248
+ factors: data.items.map((f) => ({
249
+ id: f.id,
250
+ type: f.factorType ?? null,
251
+ provider: f.provider ?? null,
252
+ name: f.vendorName ?? null,
253
+ status: f.status ?? null,
254
+ enrolled: f.created ?? null,
255
+ last_updated: f.lastUpdated ?? null,
256
+ })),
257
+ });
258
+ }));
259
+ if (allowed.has("okta_search_groups"))
260
+ server.registerTool("okta_search_groups", {
261
+ description: "Find groups whose name starts with `query` (all groups without it). When `more` is true, call again with `cursor` set to `next`.",
262
+ inputSchema: z.object({
263
+ query: z.string().max(100).optional(),
264
+ max_results: max(100, 25),
265
+ cursor: cursorArg,
266
+ }),
267
+ annotations: readOnly,
268
+ }, ({ query, max_results, cursor }) => audited(ctx, "okta_search_groups", query ?? null, async (mark) => {
269
+ const w = words(query ?? "");
270
+ const scope = groupScope(ctx);
271
+ if (scope) {
272
+ // The key's own groups, read directly: scanning every group to find them could miss.
273
+ const found = await Promise.all([...scope].map(async (id) => {
274
+ const res = await ctx.call({ method: "GET", path: `/api/v1/groups/${id}` });
275
+ mark(res.status);
276
+ if (res.status === 404)
277
+ return null;
278
+ if (res.status < 200 || res.status >= 300)
279
+ throw oktaError(res);
280
+ return res.data;
281
+ }));
282
+ const groups = found
283
+ .filter((g) => g !== null)
284
+ .filter((g) => (g.profile?.name ?? "").toLowerCase().startsWith(w.toLowerCase()))
285
+ .map(group);
286
+ return json({ groups, more: false, next: null });
287
+ }
288
+ const data = await page(ctx, mark, `/api/v1/groups?${w ? `q=${encodeURIComponent(w)}&` : ""}limit=${max_results}${after(cursor)}`);
289
+ return json({
290
+ groups: data.items.map(group),
291
+ more: Boolean(data.after),
292
+ next: data.after,
293
+ });
294
+ }));
295
+ if (allowed.has("okta_list_group_members"))
296
+ server.registerTool("okta_list_group_members", {
297
+ description: "List the people in a group. When `more` is true, call again with `cursor` set to `next`.",
298
+ inputSchema: z.object({
299
+ group_id: groupId,
300
+ max_results: max(200, 50),
301
+ cursor: cursorArg,
302
+ }),
303
+ annotations: readOnly,
304
+ }, ({ group_id, max_results, cursor }) => audited(ctx, "okta_list_group_members", group_id, async (mark) => {
305
+ checkGroup(groupScope(ctx), group_id);
306
+ const data = await page(ctx, mark, `/api/v1/groups/${group_id}/users?limit=${max_results}${after(cursor)}`);
307
+ return json({
308
+ people: data.items.map(person),
309
+ more: Boolean(data.after),
310
+ next: data.after,
311
+ });
312
+ }));
313
+ if (allowed.has("okta_list_apps"))
314
+ server.registerTool("okta_list_apps", {
315
+ description: "List apps in Okta: those assigned to `user` when given, and with a name starting with `query` when given. When `more` is true, call again with `cursor` set to `next`.",
316
+ inputSchema: z.object({
317
+ user: user.optional(),
318
+ query: z.string().max(100).optional(),
319
+ max_results: max(100, 25),
320
+ cursor: cursorArg,
321
+ }),
322
+ annotations: readOnly,
323
+ }, ({ user: u, query, max_results, cursor }) => audited(ctx, "okta_list_apps", u ?? query ?? null, async (mark) => {
324
+ const w = words(query ?? "");
325
+ const filter = u
326
+ ? `filter=${encodeURIComponent(`user.id eq "${(await openUser(ctx, mark, u)).user.id}"`)}&`
327
+ : "";
328
+ const q = w ? `q=${encodeURIComponent(w)}&` : "";
329
+ const data = await page(ctx, mark, `/api/v1/apps?${filter}${q}limit=${max_results}${after(cursor)}`);
330
+ return json({
331
+ apps: data.items.map((a) => ({
332
+ id: a.id,
333
+ label: a.label ?? null,
334
+ app: a.name ?? null,
335
+ status: a.status ?? null,
336
+ sign_on_mode: a.signOnMode ?? null,
337
+ })),
338
+ more: Boolean(data.after),
339
+ next: data.after,
340
+ });
341
+ }));
342
+ if (allowed.has("okta_get_user_activity"))
343
+ server.registerTool("okta_get_user_activity", {
344
+ description: "A person's recent System Log events, newest first: sign-ins, MFA challenges, lockouts, password and account changes, with outcome, IP address, place and browser. Also gives their status and last sign-in. `event_type` narrows to one Okta event type, e.g. user.session.start or user.account.lock. When `more` is true, call again with `cursor` set to `next` and the same `hours`.",
345
+ inputSchema: z.object({
346
+ user,
347
+ hours: z.number().int().min(1).max(MAX_HOURS).default(24),
348
+ event_type: z.string().max(100).optional(),
349
+ max_results: max(100, 25),
350
+ cursor: cursorArg,
351
+ }),
352
+ annotations: readOnly,
353
+ }, ({ user: u, hours, event_type, max_results, cursor }) => audited(ctx, "okta_get_user_activity", u, async (mark) => {
354
+ if (event_type !== undefined && !EVENT_TYPE.test(event_type))
355
+ throw new Denied("Give an Okta event type such as user.session.start");
356
+ const window = logWindow(cursor);
357
+ const { user: p, scope } = await openUser(ctx, mark, u);
358
+ const since = new Date(Date.parse(window.until) - hours * 3600_000).toISOString();
359
+ const filter = `(actor.id eq "${p.id}" or target.id eq "${p.id}")${event_type ? ` and eventType eq "${event_type}"` : ""}`;
360
+ const data = await page(ctx, mark, `/api/v1/logs?since=${since}&until=${window.until}&sortOrder=DESCENDING&filter=${encodeURIComponent(filter)}&limit=${max_results}${after(window.after)}`);
361
+ return json({
362
+ user: person(p),
363
+ last_login: p.lastLogin ?? null,
364
+ events: data.items.map((e) => event(e, p.id, Boolean(scope))),
365
+ more: Boolean(data.after),
366
+ next: data.after ? `${window.until}~${data.after}` : null,
367
+ });
368
+ }));
369
+ const membership = (tool, add) => server.registerTool(tool, {
370
+ description: add
371
+ ? "Add a person to a group. Membership can give them apps and access."
372
+ : "Remove a person from a group. They lose what the group gave them.",
373
+ inputSchema: z.object({ user, group_id: groupId }),
374
+ annotations: write(false),
375
+ }, ({ user: u, group_id }) => audited(ctx, tool, `${u} ${add ? "to" : "from"} ${group_id}`, async (mark) => {
376
+ checkGroup(groupScope(ctx), group_id);
377
+ const { user: p } = await openUser(ctx, mark, u);
378
+ await ok(ctx, mark, {
379
+ method: add ? "PUT" : "DELETE",
380
+ path: `/api/v1/groups/${group_id}/users/${p.id}`,
381
+ });
382
+ return json({ user: person(p), group_id, member: add });
383
+ }));
384
+ if (allowed.has("okta_add_group_member"))
385
+ membership("okta_add_group_member", true);
386
+ if (allowed.has("okta_remove_group_member"))
387
+ membership("okta_remove_group_member", false);
388
+ // One action on one person: read and checked first, then the call on their id.
389
+ const action = (tool, description, destructive, path, done) => server.registerTool(tool, { description, inputSchema: z.object({ user }), annotations: write(destructive) }, ({ user: u }) => audited(ctx, tool, u, async (mark) => {
390
+ const { user: p } = await openUser(ctx, mark, u);
391
+ await ok(ctx, mark, path(p.id));
392
+ return json({ user: person(p), done });
393
+ }));
394
+ const lifecycle = (id, step, query = "") => ({
395
+ method: "POST",
396
+ path: `/api/v1/users/${id}/lifecycle/${step}${query}`,
397
+ });
398
+ if (allowed.has("okta_unlock_user"))
399
+ action("okta_unlock_user", "Unlock a person whose account is locked out (status LOCKED_OUT) so they can sign in again with their password.", false, (id) => lifecycle(id, "unlock"), "Unlocked");
400
+ if (allowed.has("okta_send_password_reset"))
401
+ action("okta_send_password_reset", "Email a person a link to set a new password. Their current password stops working until they do. The link goes only to them.", false,
402
+ // Always emailed: without sendEmail Okta would answer the reset link itself.
403
+ (id) => lifecycle(id, "reset_password", "?sendEmail=true"), "Okta emailed them a password reset link");
404
+ if (allowed.has("okta_suspend_user"))
405
+ action("okta_suspend_user", "Suspend a person: they cannot sign in until unsuspended. Their apps and groups are kept.", true, (id) => lifecycle(id, "suspend"), "Suspended");
406
+ if (allowed.has("okta_unsuspend_user"))
407
+ action("okta_unsuspend_user", "Unsuspend a suspended person so they can sign in again.", false, (id) => lifecycle(id, "unsuspend"), "Unsuspended");
408
+ if (allowed.has("okta_clear_sessions"))
409
+ action("okta_clear_sessions", "Sign a person out everywhere: ends their Okta sessions and revokes the tokens apps got through Okta.", true, (id) => ({ method: "DELETE", path: `/api/v1/users/${id}/sessions?oauthTokens=true` }), "Signed out everywhere");
410
+ if (allowed.has("okta_deactivate_user"))
411
+ action("okta_deactivate_user", "Deactivate a person: they can no longer sign in, and apps set up for it remove their accounts. Only an administrator can reactivate them.", true, (id) => lifecycle(id, "deactivate", "?sendEmail=false"), "Deactivated");
412
+ if (allowed.has("okta_reset_factor"))
413
+ server.registerTool("okta_reset_factor", {
414
+ description: "Remove one of a person's MFA factors (id from okta_list_factors), e.g. after a lost phone. They set it up again at their next sign-in.",
415
+ inputSchema: z.object({ user, factor_id: z.string().max(20) }),
416
+ annotations: write(true),
417
+ }, ({ user: u, factor_id }) => audited(ctx, "okta_reset_factor", `${u} factor ${factor_id}`, async (mark) => {
418
+ if (!FACTOR_ID.test(factor_id))
419
+ throw new Denied("Give a factor id from okta_list_factors");
420
+ const { user: p } = await openUser(ctx, mark, u);
421
+ await ok(ctx, mark, {
422
+ method: "DELETE",
423
+ path: `/api/v1/users/${p.id}/factors/${factor_id}`,
424
+ });
425
+ return json({ user: person(p), factor_id, done: "Factor removed" });
426
+ }));
427
+ },
428
+ };
429
+ //# sourceMappingURL=tools.js.map