chub-dev 0.1.0 → 0.1.2-beta.0
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.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1171 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: identity
|
|
3
|
+
description: "Okta Node.js SDK coding guidelines for the Okta Management API using official libraries"
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "7.3.0"
|
|
7
|
+
updated-on: "2026-03-02"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "okta,identity,sso,oauth,authentication"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Okta Node.js SDK Coding Guidelines
|
|
13
|
+
|
|
14
|
+
You are an Okta API coding expert. Help me with writing code using the Okta Management API calling the official libraries and SDKs.
|
|
15
|
+
|
|
16
|
+
You can find the official SDK documentation and code samples here:
|
|
17
|
+
https://developer.okta.com/docs/reference/api/users/
|
|
18
|
+
https://github.com/okta/okta-sdk-nodejs
|
|
19
|
+
|
|
20
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
21
|
+
|
|
22
|
+
Always use the official Okta Node.js SDK to interact with the Okta Management API. This is the standard library for all Okta Management API interactions. Do not use deprecated packages or the authentication SDK for management tasks.
|
|
23
|
+
|
|
24
|
+
- **Library Name:** Okta Node.js SDK
|
|
25
|
+
- **NPM Package:** `@okta/okta-sdk-nodejs`
|
|
26
|
+
- **Current Version:** 7.3.0
|
|
27
|
+
- **Authentication SDK (Different Use Case):** `@okta/okta-auth-js` - Only for end-user authentication flows, NOT for management API
|
|
28
|
+
|
|
29
|
+
**Installation:**
|
|
30
|
+
|
|
31
|
+
- **Correct:** `npm install @okta/okta-sdk-nodejs`
|
|
32
|
+
|
|
33
|
+
**APIs and Usage:**
|
|
34
|
+
|
|
35
|
+
- **Correct:** `const okta = require('@okta/okta-sdk-nodejs')`
|
|
36
|
+
- **Correct:** `const client = new okta.Client({ orgUrl, token })`
|
|
37
|
+
- **Correct:** `await client.userApi.createUser({ body: newUser })`
|
|
38
|
+
- **Correct:** `await client.groupApi.createGroup({ group: newGroup })`
|
|
39
|
+
- **Correct:** `await client.applicationApi.createApplication({ application })`
|
|
40
|
+
- **Incorrect:** Using `@okta/okta-auth-js` for management operations
|
|
41
|
+
- **Incorrect:** Direct HTTP calls without SDK
|
|
42
|
+
|
|
43
|
+
## System Requirements
|
|
44
|
+
|
|
45
|
+
The Okta Node.js SDK requires:
|
|
46
|
+
- Node.js v12.0.0 or higher
|
|
47
|
+
- An Okta organization URL
|
|
48
|
+
- An API token or OAuth 2.0 credentials
|
|
49
|
+
|
|
50
|
+
## Initialization and API Authentication
|
|
51
|
+
|
|
52
|
+
The `@okta/okta-sdk-nodejs` library requires creating a `Client` instance for all API calls.
|
|
53
|
+
|
|
54
|
+
### API Token Authentication (Simple)
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
58
|
+
|
|
59
|
+
const client = new okta.Client({
|
|
60
|
+
orgUrl: 'https://dev-1234.okta.com',
|
|
61
|
+
token: process.env.OKTA_API_TOKEN
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### OAuth 2.0 Private Key Authentication (Recommended for Service Apps)
|
|
66
|
+
|
|
67
|
+
When using OAuth 2.0 with private key authentication, you don't need an API token. The SDK automatically requests access tokens.
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
71
|
+
|
|
72
|
+
const client = new okta.Client({
|
|
73
|
+
orgUrl: 'https://dev-1234.okta.com',
|
|
74
|
+
authorizationMode: 'PrivateKey',
|
|
75
|
+
clientId: process.env.OKTA_CLIENT_ID,
|
|
76
|
+
scopes: ['okta.users.manage', 'okta.groups.manage'],
|
|
77
|
+
privateKey: process.env.OKTA_PRIVATE_KEY, // JWK JSON string or PEM format
|
|
78
|
+
keyId: process.env.OKTA_KEY_ID // Optional if kid is in JWK
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Private Key Formats
|
|
83
|
+
|
|
84
|
+
The `privateKey` parameter accepts:
|
|
85
|
+
|
|
86
|
+
- **JWK (JSON Web Key) as string:**
|
|
87
|
+
```javascript
|
|
88
|
+
privateKey: '{"kty":"RSA","kid":"my-key-id","n":"...","e":"AQAB","d":"..."}'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- **JWK as object:**
|
|
92
|
+
```javascript
|
|
93
|
+
privateKey: {
|
|
94
|
+
kty: 'RSA',
|
|
95
|
+
kid: 'my-key-id',
|
|
96
|
+
n: '...',
|
|
97
|
+
e: 'AQAB',
|
|
98
|
+
d: '...'
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- **PEM format:**
|
|
103
|
+
```javascript
|
|
104
|
+
privateKey: `-----BEGIN PRIVATE KEY-----
|
|
105
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
|
|
106
|
+
-----END PRIVATE KEY-----`
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## User Management
|
|
110
|
+
|
|
111
|
+
### Create a User
|
|
112
|
+
|
|
113
|
+
Create a new user with profile information and password:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
117
|
+
const client = new okta.Client({ orgUrl, token });
|
|
118
|
+
|
|
119
|
+
async function createUser() {
|
|
120
|
+
const newUser = {
|
|
121
|
+
profile: {
|
|
122
|
+
firstName: 'John',
|
|
123
|
+
lastName: 'Doe',
|
|
124
|
+
email: 'john.doe@example.com',
|
|
125
|
+
login: 'john.doe@example.com'
|
|
126
|
+
},
|
|
127
|
+
credentials: {
|
|
128
|
+
password: {
|
|
129
|
+
value: 'SecurePassword123!'
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const user = await client.userApi.createUser({ body: newUser });
|
|
135
|
+
console.log('Created user:', user.id);
|
|
136
|
+
return user;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Create User with Activation
|
|
141
|
+
|
|
142
|
+
Create and automatically activate a user:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
async function createAndActivateUser() {
|
|
146
|
+
const newUser = {
|
|
147
|
+
profile: {
|
|
148
|
+
firstName: 'Jane',
|
|
149
|
+
lastName: 'Smith',
|
|
150
|
+
email: 'jane.smith@example.com',
|
|
151
|
+
login: 'jane.smith@example.com'
|
|
152
|
+
},
|
|
153
|
+
credentials: {
|
|
154
|
+
password: {
|
|
155
|
+
value: 'SecurePassword123!'
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const user = await client.userApi.createUser({
|
|
161
|
+
body: newUser,
|
|
162
|
+
activate: true
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
console.log('Created and activated user:', user.id);
|
|
166
|
+
return user;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Get a User
|
|
171
|
+
|
|
172
|
+
Retrieve a user by ID or login:
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
async function getUser() {
|
|
176
|
+
// By user ID
|
|
177
|
+
let user = await client.userApi.getUser({
|
|
178
|
+
userId: 'ausmvdt5xg8wRVI1d0g3'
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// By login email
|
|
182
|
+
user = await client.userApi.getUser({
|
|
183
|
+
userId: 'john.doe@example.com'
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
console.log('User:', user.profile.firstName, user.profile.lastName);
|
|
187
|
+
return user;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### List All Users
|
|
192
|
+
|
|
193
|
+
Iterate through all users in your organization:
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
async function listAllUsers() {
|
|
197
|
+
const collection = await client.userApi.listUsers();
|
|
198
|
+
|
|
199
|
+
// Using .each() method
|
|
200
|
+
await collection.each(user => {
|
|
201
|
+
console.log(`${user.profile.firstName} ${user.profile.lastName} (${user.profile.email})`);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### List Users with Async Iteration
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
async function listUsersAsyncIteration() {
|
|
210
|
+
const collection = await client.userApi.listUsers();
|
|
211
|
+
|
|
212
|
+
// Using for...await
|
|
213
|
+
for await (let user of collection) {
|
|
214
|
+
console.log(`User ID: ${user.id}, Name: ${user.profile.firstName} ${user.profile.lastName}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Search Users by Query
|
|
220
|
+
|
|
221
|
+
Search users using simple query string:
|
|
222
|
+
|
|
223
|
+
```javascript
|
|
224
|
+
async function searchUsersByName() {
|
|
225
|
+
const collection = await client.userApi.listUsers({
|
|
226
|
+
q: 'Robert'
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
for await (let user of collection) {
|
|
230
|
+
console.log('Found user:', user.profile.email);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Search Users with SCIM Filter
|
|
236
|
+
|
|
237
|
+
Use SCIM expressions for precise filtering:
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
async function searchUsersWithFilter() {
|
|
241
|
+
// SCIM filter for exact match
|
|
242
|
+
const collection = await client.userApi.listUsers({
|
|
243
|
+
search: 'profile.nickName eq "bobby"'
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
for await (let user of collection) {
|
|
247
|
+
console.log('Found user:', user.profile.email);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Filter Users by Time
|
|
253
|
+
|
|
254
|
+
Find users updated after a specific time:
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
async function findRecentlyUpdatedUsers() {
|
|
258
|
+
const collection = await client.userApi.listUsers({
|
|
259
|
+
filter: 'lastUpdated gt "2025-01-01T00:00:00.000Z"'
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
for await (let user of collection) {
|
|
263
|
+
console.log('Recently updated:', user.profile.email, 'at', user.lastUpdated);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Update a User
|
|
269
|
+
|
|
270
|
+
Modify user profile information:
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
async function updateUser(userId) {
|
|
274
|
+
const user = await client.userApi.getUser({ userId });
|
|
275
|
+
|
|
276
|
+
// Update profile fields
|
|
277
|
+
user.profile.nickName = 'Johnny';
|
|
278
|
+
user.profile.mobilePhone = '+1-555-123-4567';
|
|
279
|
+
|
|
280
|
+
await client.userApi.updateUser({
|
|
281
|
+
userId: user.id,
|
|
282
|
+
user: user
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
console.log('User updated successfully');
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Partial Update a User
|
|
290
|
+
|
|
291
|
+
Update specific fields without retrieving the full user object:
|
|
292
|
+
|
|
293
|
+
```javascript
|
|
294
|
+
async function partialUpdateUser(userId) {
|
|
295
|
+
const updates = {
|
|
296
|
+
profile: {
|
|
297
|
+
nickName: 'JD',
|
|
298
|
+
department: 'Engineering'
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await client.userApi.updateUser({
|
|
303
|
+
userId: userId,
|
|
304
|
+
user: updates
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
console.log('User partially updated');
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Deactivate a User
|
|
312
|
+
|
|
313
|
+
Deactivate a user account:
|
|
314
|
+
|
|
315
|
+
```javascript
|
|
316
|
+
async function deactivateUser(userId) {
|
|
317
|
+
await client.userApi.deactivateUser({ userId });
|
|
318
|
+
console.log('User deactivated');
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Delete a User
|
|
323
|
+
|
|
324
|
+
Permanently delete a user (must be deactivated first):
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
async function deleteUser(userId) {
|
|
328
|
+
// First deactivate
|
|
329
|
+
await client.userApi.deactivateUser({ userId });
|
|
330
|
+
|
|
331
|
+
// Then delete
|
|
332
|
+
await client.userApi.deleteUser({ userId });
|
|
333
|
+
|
|
334
|
+
console.log('User deleted permanently');
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Reactivate a User
|
|
339
|
+
|
|
340
|
+
Reactivate a previously deactivated user:
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
async function reactivateUser(userId) {
|
|
344
|
+
await client.userApi.activateUser({
|
|
345
|
+
userId: userId,
|
|
346
|
+
sendEmail: false
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
console.log('User reactivated');
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Suspend and Unsuspend User
|
|
354
|
+
|
|
355
|
+
Temporarily suspend a user:
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
async function suspendUser(userId) {
|
|
359
|
+
await client.userApi.suspendUser({ userId });
|
|
360
|
+
console.log('User suspended');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function unsuspendUser(userId) {
|
|
364
|
+
await client.userApi.unsuspendUser({ userId });
|
|
365
|
+
console.log('User unsuspended');
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Reset User Password
|
|
370
|
+
|
|
371
|
+
Send a password reset email:
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
async function resetUserPassword(userId) {
|
|
375
|
+
await client.userApi.resetPassword({
|
|
376
|
+
userId: userId,
|
|
377
|
+
sendEmail: true
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
console.log('Password reset email sent');
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Expire User Password
|
|
385
|
+
|
|
386
|
+
Force a user to change password on next login:
|
|
387
|
+
|
|
388
|
+
```javascript
|
|
389
|
+
async function expireUserPassword(userId) {
|
|
390
|
+
const user = await client.userApi.expirePassword({
|
|
391
|
+
userId: userId
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
console.log('Password expired for user:', user.id);
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Group Management
|
|
399
|
+
|
|
400
|
+
### Create a Group
|
|
401
|
+
|
|
402
|
+
Create a new group:
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
async function createGroup() {
|
|
406
|
+
const newGroup = {
|
|
407
|
+
profile: {
|
|
408
|
+
name: 'Engineering Team',
|
|
409
|
+
description: 'All engineering department members'
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
const group = await client.groupApi.createGroup({ group: newGroup });
|
|
414
|
+
console.log('Created group:', group.id);
|
|
415
|
+
return group;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Get a Group
|
|
420
|
+
|
|
421
|
+
Retrieve a group by ID:
|
|
422
|
+
|
|
423
|
+
```javascript
|
|
424
|
+
async function getGroup(groupId) {
|
|
425
|
+
const group = await client.groupApi.getGroup({ groupId });
|
|
426
|
+
console.log('Group:', group.profile.name);
|
|
427
|
+
return group;
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### List All Groups
|
|
432
|
+
|
|
433
|
+
List all groups in the organization:
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
async function listAllGroups() {
|
|
437
|
+
const collection = await client.groupApi.listGroups();
|
|
438
|
+
|
|
439
|
+
for await (let group of collection) {
|
|
440
|
+
console.log(`Group: ${group.profile.name} (${group.id})`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Search Groups by Name
|
|
446
|
+
|
|
447
|
+
Search for groups matching a query:
|
|
448
|
+
|
|
449
|
+
```javascript
|
|
450
|
+
async function searchGroups() {
|
|
451
|
+
const collection = await client.groupApi.listGroups({
|
|
452
|
+
q: 'Engineering'
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
for await (let group of collection) {
|
|
456
|
+
console.log('Found group:', group.profile.name);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Update a Group
|
|
462
|
+
|
|
463
|
+
Update group profile information:
|
|
464
|
+
|
|
465
|
+
```javascript
|
|
466
|
+
async function updateGroup(groupId) {
|
|
467
|
+
const group = await client.groupApi.getGroup({ groupId });
|
|
468
|
+
|
|
469
|
+
group.profile.description = 'Updated description';
|
|
470
|
+
|
|
471
|
+
await client.groupApi.updateGroup({
|
|
472
|
+
groupId: group.id,
|
|
473
|
+
group: group
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
console.log('Group updated');
|
|
477
|
+
}
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Delete a Group
|
|
481
|
+
|
|
482
|
+
Delete a group:
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
async function deleteGroup(groupId) {
|
|
486
|
+
await client.groupApi.deleteGroup({ groupId });
|
|
487
|
+
console.log('Group deleted');
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Assign User to Group
|
|
492
|
+
|
|
493
|
+
Add a user to a group:
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
async function assignUserToGroup(groupId, userId) {
|
|
497
|
+
await client.groupApi.assignUserToGroup({
|
|
498
|
+
groupId: groupId,
|
|
499
|
+
userId: userId
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
console.log(`User ${userId} added to group ${groupId}`);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Remove User from Group
|
|
507
|
+
|
|
508
|
+
Remove a user from a group:
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
async function removeUserFromGroup(groupId, userId) {
|
|
512
|
+
await client.groupApi.unassignUserFromGroup({
|
|
513
|
+
groupId: groupId,
|
|
514
|
+
userId: userId
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
console.log(`User ${userId} removed from group ${groupId}`);
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### List Group Members
|
|
522
|
+
|
|
523
|
+
Get all users in a group:
|
|
524
|
+
|
|
525
|
+
```javascript
|
|
526
|
+
async function listGroupMembers(groupId) {
|
|
527
|
+
const collection = await client.groupApi.listGroupUsers({ groupId });
|
|
528
|
+
|
|
529
|
+
for await (let user of collection) {
|
|
530
|
+
console.log(`Member: ${user.profile.firstName} ${user.profile.lastName}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### List User's Groups
|
|
536
|
+
|
|
537
|
+
Get all groups a user belongs to:
|
|
538
|
+
|
|
539
|
+
```javascript
|
|
540
|
+
async function listUserGroups(userId) {
|
|
541
|
+
const collection = await client.userApi.listUserGroups({ userId });
|
|
542
|
+
|
|
543
|
+
for await (let group of collection) {
|
|
544
|
+
console.log(`User is in group: ${group.profile.name}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Application Management
|
|
550
|
+
|
|
551
|
+
### Create a Basic Auth Application
|
|
552
|
+
|
|
553
|
+
```javascript
|
|
554
|
+
async function createBasicAuthApp() {
|
|
555
|
+
const application = {
|
|
556
|
+
name: 'template_basic_auth',
|
|
557
|
+
label: 'Sample Basic Auth App',
|
|
558
|
+
signOnMode: 'BASIC_AUTH',
|
|
559
|
+
settings: {
|
|
560
|
+
app: {
|
|
561
|
+
url: 'https://example.com/auth.htm',
|
|
562
|
+
authURL: 'https://example.com/login.html'
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const app = await client.applicationApi.createApplication({
|
|
568
|
+
application: application
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
console.log('Created application:', app.id);
|
|
572
|
+
return app;
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Create a SAML 2.0 Application
|
|
577
|
+
|
|
578
|
+
```javascript
|
|
579
|
+
async function createSAMLApp() {
|
|
580
|
+
const application = {
|
|
581
|
+
name: 'template_saml_2_0',
|
|
582
|
+
label: 'SAML 2.0 App',
|
|
583
|
+
signOnMode: 'SAML_2_0',
|
|
584
|
+
settings: {
|
|
585
|
+
signOn: {
|
|
586
|
+
defaultRelayState: '',
|
|
587
|
+
ssoAcsUrl: 'https://example.com/sso/saml',
|
|
588
|
+
recipient: 'https://example.com/sso/saml',
|
|
589
|
+
destination: 'https://example.com/sso/saml',
|
|
590
|
+
audience: 'https://example.com',
|
|
591
|
+
idpIssuer: 'http://www.okta.com/${org.externalKey}',
|
|
592
|
+
subjectNameIdTemplate: '${user.userName}',
|
|
593
|
+
subjectNameIdFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
|
594
|
+
responseSigned: true,
|
|
595
|
+
assertionSigned: true,
|
|
596
|
+
signatureAlgorithm: 'RSA_SHA256',
|
|
597
|
+
digestAlgorithm: 'SHA256',
|
|
598
|
+
honorForceAuthn: true,
|
|
599
|
+
authnContextClassRef: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
const app = await client.applicationApi.createApplication({
|
|
605
|
+
application: application
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
console.log('Created SAML application:', app.id);
|
|
609
|
+
return app;
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Create an OAuth 2.0 Application
|
|
614
|
+
|
|
615
|
+
```javascript
|
|
616
|
+
async function createOAuthApp() {
|
|
617
|
+
const application = {
|
|
618
|
+
name: 'oidc_client',
|
|
619
|
+
label: 'OAuth 2.0 App',
|
|
620
|
+
signOnMode: 'OPENID_CONNECT',
|
|
621
|
+
credentials: {
|
|
622
|
+
oauthClient: {
|
|
623
|
+
token_endpoint_auth_method: 'client_secret_post'
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
settings: {
|
|
627
|
+
oauthClient: {
|
|
628
|
+
client_uri: 'https://example.com',
|
|
629
|
+
logo_uri: 'https://example.com/logo.png',
|
|
630
|
+
redirect_uris: ['https://example.com/oauth/callback'],
|
|
631
|
+
response_types: ['code'],
|
|
632
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
633
|
+
application_type: 'web'
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
const app = await client.applicationApi.createApplication({
|
|
639
|
+
application: application
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
console.log('Created OAuth app:', app.id);
|
|
643
|
+
console.log('Client ID:', app.credentials.oauthClient.client_id);
|
|
644
|
+
console.log('Client Secret:', app.credentials.oauthClient.client_secret);
|
|
645
|
+
return app;
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Get an Application
|
|
650
|
+
|
|
651
|
+
Retrieve an application by ID:
|
|
652
|
+
|
|
653
|
+
```javascript
|
|
654
|
+
async function getApplication(appId) {
|
|
655
|
+
const app = await client.applicationApi.getApplication({
|
|
656
|
+
appId: appId
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
console.log('Application:', app.label);
|
|
660
|
+
return app;
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### List All Applications
|
|
665
|
+
|
|
666
|
+
```javascript
|
|
667
|
+
async function listAllApplications() {
|
|
668
|
+
const collection = await client.applicationApi.listApplications();
|
|
669
|
+
|
|
670
|
+
for await (let app of collection) {
|
|
671
|
+
console.log(`App: ${app.label} (${app.id})`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Update an Application
|
|
677
|
+
|
|
678
|
+
```javascript
|
|
679
|
+
async function updateApplication(appId) {
|
|
680
|
+
const app = await client.applicationApi.getApplication({ appId });
|
|
681
|
+
|
|
682
|
+
app.label = 'Updated Application Name';
|
|
683
|
+
|
|
684
|
+
await client.applicationApi.updateApplication({
|
|
685
|
+
appId: app.id,
|
|
686
|
+
application: app
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
console.log('Application updated');
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Delete an Application
|
|
694
|
+
|
|
695
|
+
```javascript
|
|
696
|
+
async function deleteApplication(appId) {
|
|
697
|
+
await client.applicationApi.deactivateApplication({ appId });
|
|
698
|
+
await client.applicationApi.deleteApplication({ appId });
|
|
699
|
+
console.log('Application deleted');
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### Assign User to Application
|
|
704
|
+
|
|
705
|
+
```javascript
|
|
706
|
+
async function assignUserToApplication(appId, userId) {
|
|
707
|
+
const appUser = await client.applicationApi.assignUserToApplication({
|
|
708
|
+
appId: appId,
|
|
709
|
+
appUser: {
|
|
710
|
+
id: userId
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
console.log('User assigned to application:', appUser.id);
|
|
715
|
+
return appUser;
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### Assign User with Profile to Application
|
|
720
|
+
|
|
721
|
+
```javascript
|
|
722
|
+
async function assignUserWithProfile(appId, userId) {
|
|
723
|
+
const appUser = await client.applicationApi.assignUserToApplication({
|
|
724
|
+
appId: appId,
|
|
725
|
+
appUser: {
|
|
726
|
+
id: userId,
|
|
727
|
+
credentials: {
|
|
728
|
+
userName: 'user@example.com',
|
|
729
|
+
password: { value: 'AppSpecificPassword123!' }
|
|
730
|
+
},
|
|
731
|
+
profile: {
|
|
732
|
+
role: 'Admin',
|
|
733
|
+
department: 'Engineering'
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
console.log('User assigned with profile');
|
|
739
|
+
return appUser;
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### Remove User from Application
|
|
744
|
+
|
|
745
|
+
```javascript
|
|
746
|
+
async function removeUserFromApplication(appId, userId) {
|
|
747
|
+
await client.applicationApi.unassignUserFromApplication({
|
|
748
|
+
appId: appId,
|
|
749
|
+
userId: userId
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
console.log('User removed from application');
|
|
753
|
+
}
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### Assign Group to Application
|
|
757
|
+
|
|
758
|
+
```javascript
|
|
759
|
+
async function assignGroupToApplication(appId, groupId) {
|
|
760
|
+
const assignment = await client.applicationApi.assignGroupToApplication({
|
|
761
|
+
appId: appId,
|
|
762
|
+
groupId: groupId,
|
|
763
|
+
applicationGroupAssignment: {}
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
console.log('Group assigned to application');
|
|
767
|
+
return assignment;
|
|
768
|
+
}
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
### Remove Group from Application
|
|
772
|
+
|
|
773
|
+
```javascript
|
|
774
|
+
async function removeGroupFromApplication(appId, groupId) {
|
|
775
|
+
await client.applicationApi.unassignApplicationFromGroup({
|
|
776
|
+
appId: appId,
|
|
777
|
+
groupId: groupId
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
console.log('Group removed from application');
|
|
781
|
+
}
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### List Application Users
|
|
785
|
+
|
|
786
|
+
Get all users assigned to an application:
|
|
787
|
+
|
|
788
|
+
```javascript
|
|
789
|
+
async function listApplicationUsers(appId) {
|
|
790
|
+
const collection = await client.applicationApi.listApplicationUsers({
|
|
791
|
+
appId: appId
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
for await (let appUser of collection) {
|
|
795
|
+
console.log(`User ${appUser.id} assigned to app`);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
### List Application Groups
|
|
801
|
+
|
|
802
|
+
Get all groups assigned to an application:
|
|
803
|
+
|
|
804
|
+
```javascript
|
|
805
|
+
async function listApplicationGroups(appId) {
|
|
806
|
+
const collection = await client.applicationApi.listApplicationGroupAssignments({
|
|
807
|
+
appId: appId
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
for await (let assignment of collection) {
|
|
811
|
+
console.log(`Group ${assignment.id} assigned to app`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
## Authentication and Sessions
|
|
817
|
+
|
|
818
|
+
### List Active User Sessions
|
|
819
|
+
|
|
820
|
+
```javascript
|
|
821
|
+
async function listUserSessions(userId) {
|
|
822
|
+
const collection = await client.userApi.listUserSessions({ userId });
|
|
823
|
+
|
|
824
|
+
for await (let session of collection) {
|
|
825
|
+
console.log(`Session ID: ${session.id}, Created: ${session.createdAt}`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
### Clear User Sessions
|
|
831
|
+
|
|
832
|
+
Clear all sessions for a user:
|
|
833
|
+
|
|
834
|
+
```javascript
|
|
835
|
+
async function clearUserSessions(userId) {
|
|
836
|
+
await client.userApi.clearUserSessions({ userId });
|
|
837
|
+
console.log('All user sessions cleared');
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
## Error Handling
|
|
842
|
+
|
|
843
|
+
Always wrap API calls in try-catch blocks:
|
|
844
|
+
|
|
845
|
+
```javascript
|
|
846
|
+
async function handleErrors() {
|
|
847
|
+
try {
|
|
848
|
+
const user = await client.userApi.getUser({
|
|
849
|
+
userId: 'nonexistent@example.com'
|
|
850
|
+
});
|
|
851
|
+
} catch (error) {
|
|
852
|
+
if (error.status === 404) {
|
|
853
|
+
console.error('User not found');
|
|
854
|
+
} else if (error.status === 401) {
|
|
855
|
+
console.error('Authentication failed - check your API token');
|
|
856
|
+
} else if (error.status === 403) {
|
|
857
|
+
console.error('Forbidden - insufficient permissions');
|
|
858
|
+
} else if (error.status === 429) {
|
|
859
|
+
console.error('Rate limit exceeded');
|
|
860
|
+
} else {
|
|
861
|
+
console.error('API Error:', error.message);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
### Comprehensive Error Handling Pattern
|
|
868
|
+
|
|
869
|
+
```javascript
|
|
870
|
+
async function createUserWithErrorHandling(userData) {
|
|
871
|
+
try {
|
|
872
|
+
const newUser = {
|
|
873
|
+
profile: {
|
|
874
|
+
firstName: userData.firstName,
|
|
875
|
+
lastName: userData.lastName,
|
|
876
|
+
email: userData.email,
|
|
877
|
+
login: userData.email
|
|
878
|
+
},
|
|
879
|
+
credentials: {
|
|
880
|
+
password: {
|
|
881
|
+
value: userData.password
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
const user = await client.userApi.createUser({ body: newUser });
|
|
887
|
+
console.log('User created successfully:', user.id);
|
|
888
|
+
return { success: true, user };
|
|
889
|
+
|
|
890
|
+
} catch (error) {
|
|
891
|
+
console.error('Error creating user:', error.message);
|
|
892
|
+
|
|
893
|
+
if (error.status === 400) {
|
|
894
|
+
console.error('Bad request - check user data format');
|
|
895
|
+
if (error.body && error.body.errorCauses) {
|
|
896
|
+
error.body.errorCauses.forEach(cause => {
|
|
897
|
+
console.error('Error cause:', cause.errorSummary);
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
} else if (error.status === 401) {
|
|
901
|
+
console.error('Authentication failed');
|
|
902
|
+
} else if (error.status === 403) {
|
|
903
|
+
console.error('Forbidden - insufficient permissions');
|
|
904
|
+
} else if (error.status === 409) {
|
|
905
|
+
console.error('Conflict - user already exists');
|
|
906
|
+
} else if (error.status === 429) {
|
|
907
|
+
console.error('Rate limit exceeded - retry after delay');
|
|
908
|
+
} else if (error.status >= 500) {
|
|
909
|
+
console.error('Server error - Okta service issue');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
return { success: false, error: error.message };
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
## Pagination
|
|
918
|
+
|
|
919
|
+
Collections automatically handle pagination. Use `limit` to control page size:
|
|
920
|
+
|
|
921
|
+
```javascript
|
|
922
|
+
async function paginateUsers() {
|
|
923
|
+
const collection = await client.userApi.listUsers({
|
|
924
|
+
limit: 20 // 20 users per page
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
for await (let user of collection) {
|
|
928
|
+
// SDK automatically fetches next pages
|
|
929
|
+
console.log(user.profile.email);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
### Manual Pagination with After Parameter
|
|
935
|
+
|
|
936
|
+
```javascript
|
|
937
|
+
async function manualPagination() {
|
|
938
|
+
let after;
|
|
939
|
+
let pageCount = 0;
|
|
940
|
+
|
|
941
|
+
do {
|
|
942
|
+
const response = await client.userApi.listUsers({
|
|
943
|
+
limit: 10,
|
|
944
|
+
after: after
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
const users = response.users || [];
|
|
948
|
+
console.log(`Page ${++pageCount}: ${users.length} users`);
|
|
949
|
+
|
|
950
|
+
users.forEach(user => {
|
|
951
|
+
console.log(' -', user.profile.email);
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
// Check if there's a next page
|
|
955
|
+
after = response.nextPage ? response.nextPage.after : null;
|
|
956
|
+
|
|
957
|
+
} while (after);
|
|
958
|
+
}
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
## Rate Limiting
|
|
962
|
+
|
|
963
|
+
The SDK automatically handles rate limiting with retry logic. Be aware of Okta rate limits:
|
|
964
|
+
|
|
965
|
+
- Most endpoints: 600 requests per minute
|
|
966
|
+
- Authentication endpoints: Varies by org tier
|
|
967
|
+
- Concurrent requests: Limited per org
|
|
968
|
+
|
|
969
|
+
```javascript
|
|
970
|
+
async function bulkOperationWithRateLimit() {
|
|
971
|
+
const users = []; // Large array of users to create
|
|
972
|
+
|
|
973
|
+
for (const userData of users) {
|
|
974
|
+
try {
|
|
975
|
+
const user = await client.userApi.createUser({ body: userData });
|
|
976
|
+
console.log('Created user:', user.id);
|
|
977
|
+
|
|
978
|
+
// Optional: Add delay between requests
|
|
979
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
980
|
+
|
|
981
|
+
} catch (error) {
|
|
982
|
+
if (error.status === 429) {
|
|
983
|
+
console.log('Rate limit hit, waiting before retry...');
|
|
984
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
985
|
+
// Retry logic here
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
## Working with Custom User Attributes
|
|
993
|
+
|
|
994
|
+
### Create User with Custom Attributes
|
|
995
|
+
|
|
996
|
+
```javascript
|
|
997
|
+
async function createUserWithCustomAttributes() {
|
|
998
|
+
const newUser = {
|
|
999
|
+
profile: {
|
|
1000
|
+
firstName: 'John',
|
|
1001
|
+
lastName: 'Doe',
|
|
1002
|
+
email: 'john.doe@example.com',
|
|
1003
|
+
login: 'john.doe@example.com',
|
|
1004
|
+
// Custom attributes (must be defined in user schema first)
|
|
1005
|
+
employeeId: 'EMP-12345',
|
|
1006
|
+
department: 'Engineering',
|
|
1007
|
+
costCenter: 'CC-100'
|
|
1008
|
+
},
|
|
1009
|
+
credentials: {
|
|
1010
|
+
password: {
|
|
1011
|
+
value: 'SecurePassword123!'
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
const user = await client.userApi.createUser({ body: newUser });
|
|
1017
|
+
console.log('Created user with custom attributes:', user.id);
|
|
1018
|
+
}
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
## Complete Example Application
|
|
1022
|
+
|
|
1023
|
+
```javascript
|
|
1024
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
1025
|
+
|
|
1026
|
+
// Initialize client
|
|
1027
|
+
const client = new okta.Client({
|
|
1028
|
+
orgUrl: process.env.OKTA_ORG_URL,
|
|
1029
|
+
token: process.env.OKTA_API_TOKEN
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
async function main() {
|
|
1033
|
+
try {
|
|
1034
|
+
// Create a user
|
|
1035
|
+
const newUser = {
|
|
1036
|
+
profile: {
|
|
1037
|
+
firstName: 'Alice',
|
|
1038
|
+
lastName: 'Johnson',
|
|
1039
|
+
email: 'alice.johnson@example.com',
|
|
1040
|
+
login: 'alice.johnson@example.com'
|
|
1041
|
+
},
|
|
1042
|
+
credentials: {
|
|
1043
|
+
password: { value: 'SecurePassword123!' }
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
const user = await client.userApi.createUser({
|
|
1048
|
+
body: newUser,
|
|
1049
|
+
activate: true
|
|
1050
|
+
});
|
|
1051
|
+
console.log('Created user:', user.id);
|
|
1052
|
+
|
|
1053
|
+
// Create a group
|
|
1054
|
+
const newGroup = {
|
|
1055
|
+
profile: {
|
|
1056
|
+
name: 'Project Team Alpha',
|
|
1057
|
+
description: 'Members of Project Alpha'
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
const group = await client.groupApi.createGroup({ group: newGroup });
|
|
1062
|
+
console.log('Created group:', group.id);
|
|
1063
|
+
|
|
1064
|
+
// Add user to group
|
|
1065
|
+
await client.groupApi.assignUserToGroup({
|
|
1066
|
+
groupId: group.id,
|
|
1067
|
+
userId: user.id
|
|
1068
|
+
});
|
|
1069
|
+
console.log('User added to group');
|
|
1070
|
+
|
|
1071
|
+
// Create an application
|
|
1072
|
+
const application = {
|
|
1073
|
+
name: 'template_basic_auth',
|
|
1074
|
+
label: 'Team Application',
|
|
1075
|
+
signOnMode: 'BASIC_AUTH',
|
|
1076
|
+
settings: {
|
|
1077
|
+
app: {
|
|
1078
|
+
url: 'https://example.com/app',
|
|
1079
|
+
authURL: 'https://example.com/login'
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
const app = await client.applicationApi.createApplication({
|
|
1085
|
+
application: application
|
|
1086
|
+
});
|
|
1087
|
+
console.log('Created application:', app.id);
|
|
1088
|
+
|
|
1089
|
+
// Assign group to application
|
|
1090
|
+
await client.applicationApi.assignGroupToApplication({
|
|
1091
|
+
appId: app.id,
|
|
1092
|
+
groupId: group.id,
|
|
1093
|
+
applicationGroupAssignment: {}
|
|
1094
|
+
});
|
|
1095
|
+
console.log('Group assigned to application');
|
|
1096
|
+
|
|
1097
|
+
// List all users in the group
|
|
1098
|
+
console.log('\nGroup members:');
|
|
1099
|
+
const members = await client.groupApi.listGroupUsers({ groupId: group.id });
|
|
1100
|
+
for await (let member of members) {
|
|
1101
|
+
console.log(` - ${member.profile.firstName} ${member.profile.lastName}`);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
console.error('Error:', error.message);
|
|
1106
|
+
if (error.status) {
|
|
1107
|
+
console.error('Status:', error.status);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
main();
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
## Environment Variables Setup
|
|
1116
|
+
|
|
1117
|
+
Create a `.env` file for configuration:
|
|
1118
|
+
|
|
1119
|
+
```bash
|
|
1120
|
+
OKTA_ORG_URL=https://dev-1234567.okta.com
|
|
1121
|
+
OKTA_API_TOKEN=your_api_token_here
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
Load environment variables:
|
|
1125
|
+
|
|
1126
|
+
```javascript
|
|
1127
|
+
require('dotenv').config();
|
|
1128
|
+
|
|
1129
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
1130
|
+
|
|
1131
|
+
const client = new okta.Client({
|
|
1132
|
+
orgUrl: process.env.OKTA_ORG_URL,
|
|
1133
|
+
token: process.env.OKTA_API_TOKEN
|
|
1134
|
+
});
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
## OAuth 2.0 Private Key Configuration
|
|
1138
|
+
|
|
1139
|
+
For OAuth 2.0 authentication, use environment variables:
|
|
1140
|
+
|
|
1141
|
+
```bash
|
|
1142
|
+
OKTA_ORG_URL=https://dev-1234567.okta.com
|
|
1143
|
+
OKTA_CLIENT_ID=your_client_id
|
|
1144
|
+
OKTA_PRIVATE_KEY='{"kty":"RSA","kid":"key-id","n":"...","e":"AQAB","d":"..."}'
|
|
1145
|
+
OKTA_KEY_ID=key-id
|
|
1146
|
+
OKTA_SCOPES=okta.users.manage,okta.groups.manage,okta.apps.manage
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
```javascript
|
|
1150
|
+
require('dotenv').config();
|
|
1151
|
+
const okta = require('@okta/okta-sdk-nodejs');
|
|
1152
|
+
|
|
1153
|
+
const client = new okta.Client({
|
|
1154
|
+
orgUrl: process.env.OKTA_ORG_URL,
|
|
1155
|
+
authorizationMode: 'PrivateKey',
|
|
1156
|
+
clientId: process.env.OKTA_CLIENT_ID,
|
|
1157
|
+
scopes: process.env.OKTA_SCOPES.split(','),
|
|
1158
|
+
privateKey: process.env.OKTA_PRIVATE_KEY,
|
|
1159
|
+
keyId: process.env.OKTA_KEY_ID
|
|
1160
|
+
});
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
## Useful Links
|
|
1164
|
+
|
|
1165
|
+
- Official Documentation: https://developer.okta.com/
|
|
1166
|
+
- API Reference: https://developer.okta.com/docs/reference/
|
|
1167
|
+
- Users API: https://developer.okta.com/docs/reference/api/users/
|
|
1168
|
+
- Groups API: https://developer.okta.com/docs/reference/api/groups/
|
|
1169
|
+
- Applications API: https://developer.okta.com/docs/reference/api/apps/
|
|
1170
|
+
- GitHub Repository: https://github.com/okta/okta-sdk-nodejs
|
|
1171
|
+
- NPM Package: https://www.npmjs.com/package/@okta/okta-sdk-nodejs
|