@descope/node-sdk 1.0.4-alpha.9 → 1.0.5

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Descope
3
+ Copyright (c) 2023 Descope
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,49 +1,624 @@
1
- # Descope Node.js SDK
1
+ # Descope SDK for Node.js
2
2
 
3
- Use the Descope NodeJS SDK for NodeJS/Express to quickly and easily add user authentication to your application or website.
3
+ The Descope SDK for Node.js provides convenient access to the Descope user management and authentication API
4
+ for a backend written in Node.js. You can read more on the [Descope Website](https://descope.com).
4
5
 
5
- ## Installing the SDK
6
+ ## Requirements
7
+
8
+ The SDK supports Node version 14 and above.
6
9
 
7
- Replace any instance of `<ProjectID>` in the code below with your company's Project ID, which can be found in the [Descope console](https://app.descope.com).
10
+ ## Installing the SDK
8
11
 
9
- Run the following code in your project. These commands will add the Descope SDK for Node as a project dependency, and set the `DESCOPE_PROJECT_ID` variable to a valid \<ProjectID\>.
12
+ Install the package with:
10
13
 
11
14
  ```bash
12
15
  npm i --save @descope/node-sdk
13
16
  ```
14
17
 
15
- ## What do you want to implement?
18
+ ## Setup
19
+
20
+ A Descope `Project ID` is required to initialize the SDK. Find it on the
21
+ [project page in the Descope Console](https://app.descope.com/settings/project).
22
+
23
+ ```typescript
24
+ import DescopeClient from '@descope/node-sdk';
25
+
26
+ const descopeClient = DescopeClient({ projectId: 'my-project-ID' });
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ Here are some examples how to manage and authenticate users:
32
+
33
+ ### OTP Authentication
34
+
35
+ Send a user a one-time password (OTP) using your preferred delivery method (_email / SMS_). An email address or phone number must be provided accordingly.
36
+
37
+ The user can either `sign up`, `sign in` or `sign up or in`
38
+
39
+ ```typescript
40
+ // Every user must have a login ID. All other user information is optional
41
+ const loginId = 'desmond@descope.com';
42
+ const user = {
43
+ name: 'Desmond Copland',
44
+ phone: '212-555-1234',
45
+ email: loginId,
46
+ };
47
+ await descopeClient.otp.signUp['email'](loginId, user);
48
+ ```
49
+
50
+ The user will receive a code using the selected delivery method. Verify that code using:
51
+
52
+ ```typescript
53
+ const jwtResponse = await descopeClient.otp.verify['email'](loginId, 'code');
54
+ // jwtResponse.data.sessionJwt
55
+ // jwtResponse.data.refreshJwt
56
+ ```
57
+
58
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
59
+
60
+ ### Magic Link
61
+
62
+ Send a user a Magic Link using your preferred delivery method (_email / SMS_).
63
+ The Magic Link will redirect the user to page where the its token needs to be verified.
64
+ This redirection can be configured in code, or globally in the [Descope Console](https://app.descope.com/settings/authentication/magiclink)
65
+
66
+ The user can either `sign up`, `sign in` or `sign up or in`
67
+
68
+ ```typescript
69
+ // If configured globally, the redirect URI is optional. If provided however, it will be used
70
+ // instead of any global configuration
71
+ const URI = 'http://myapp.com/verify-magic-link';
72
+ await descopeClient.magicLink.signUpOrIn['email']('desmond@descope.com', URI);
73
+ ```
74
+
75
+ To verify a magic link, your redirect page must call the validation function on the token (`t`) parameter (`https://your-redirect-address.com/verify?t=<token>`):
76
+
77
+ ```typescript
78
+ const jwtResponse = await descopeClient.magicLink.verify('token');
79
+ // jwtResponse.data.sessionJwt;
80
+ // jwtResponse.data.refreshJwt;
81
+ ```
82
+
83
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
84
+
85
+ ### Enchanted Link
86
+
87
+ Using the Enchanted Link APIs enables users to sign in by clicking a link
88
+ delivered to their email address. The email will include 3 different links,
89
+ and the user will have to click the right one, based on the 2-digit number that is
90
+ displayed when initiating the authentication process.
91
+
92
+ This method is similar to [Magic Link](#magic-link) but differs in two major ways:
93
+
94
+ - The user must choose the correct link out of the three, instead of having just one
95
+ single link.
96
+ - This supports cross-device clicking, meaning the user can try to log in on one device,
97
+ like a computer, while clicking the link on another device, for instance a mobile phone.
98
+
99
+ The Enchanted Link will redirect the user to page where the its token needs to be verified.
100
+ This redirection can be configured in code per request, or set globally in the [Descope Console](https://app.descope.com/settings/authentication/enchantedlink).
101
+
102
+ The user can either `sign up`, `sign in` or `sign up or in`
103
+
104
+ ```typescript
105
+ // If configured globally, the redirect URI is optional. If provided however, it will be used
106
+ // instead of any global configuration.
107
+ const URI = 'http://myapp.com/verify-enchanted-link';
108
+ const enchantedLinkRes = await descopeClient.enchantedLink.signIn('desmond@descope.com', URI);
109
+ enchantedLinkRes.data.linkId; // Should be displayed to the user so they can click the corresponding link in the email
110
+ enchantedLinkRes.data.pendingRef; // Used to poll for a valid session
111
+ ```
112
+
113
+ After sending the link, you must poll to receive a valid session using the `pendingRef` from
114
+ the previous step. A valid session will be returned only after the user clicks the right link.
115
+
116
+ ```typescript
117
+ // Poll for a certain number of tries / time frame. You can control the polling interval and time frame
118
+ // with the optional WaitForSessionConfig
119
+ const jwtResponse = await descopeClient.enchantedLink.waitForSession(
120
+ enchantedLinkRes.data.pendingRef,
121
+ );
122
+ // jwtResponse.data.sessionJwt;
123
+ // jwtResponse.data.refreshJwt;
124
+ ```
125
+
126
+ To verify an enchanted link, your redirect page must call the validation function on the token (`t`) parameter (`https://your-redirect-address.com/verify?t=<token>`). Once the token is verified, the session polling will receive a valid response.
127
+
128
+ ```typescript
129
+ try {
130
+ await descopeClient.enchantedLink.verify('token');
131
+ // token is invalid
132
+ } catch (error) {
133
+ // token is valid
134
+ }
135
+ ```
136
+
137
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
138
+
139
+ ### OAuth
140
+
141
+ Users can authenticate using their social logins, via the OAuth protocol. Configure your OAuth settings on the [Descope console](https://app.descope.com/settings/authentication/social). To start an OAuth flow call:
142
+
143
+ ```typescript
144
+ // Choose an oauth provider out of the supported providers
145
+ // If configured globally, the return URL is optional. If provided however, it will be used
146
+ // instead of any global configuration.
147
+
148
+ const urlRes = await descopeClient.oauth.start['google'](redirectUrl);
149
+ urlRes.data.url; // Redirect the user to the returned URL to start the OAuth redirect chain
150
+ ```
151
+
152
+ The user will authenticate with the authentication provider, and will be redirected back to the redirect URL, with an appended `code` HTTP URL parameter. Exchange it to validate the user:
153
+
154
+ ```typescript
155
+ const jwtResponse = await descopeClient.oauth.exchange('token');
156
+ // jwtResponse.data.sessionJwt;
157
+ // jwtResponse.data.refreshJwt;
158
+ ```
159
+
160
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
161
+
162
+ ### SSO/SAML
163
+
164
+ Users can authenticate to a specific tenant using SAML or Single Sign On. Configure your SSO/SAML settings on the [Descope console](https://app.descope.com/settings/authentication/sso). To start a flow call:
165
+
166
+ ```typescript
167
+ // If configured globally, the return URL is optional. If provided however, it will be used
168
+ // instead of any global configuration.
169
+ const redirectUrl = 'https://my-app.com/handle-saml';
170
+ const urlRes = await descopeClient.saml.start('tenant'); // Choose which tenant to log into. An email can also be provided here and the domain will be extracted from it
171
+ urlRes.data.url; // Redirect the user to the given returned URL to start the SSO/SAML redirect chain
172
+ ```
173
+
174
+ The user will authenticate with the authentication provider configured for that tenant, and will be redirected back to the redirect URL, with an appended `code` HTTP URL parameter. Exchange it to validate the user:
175
+
176
+ ```typescript
177
+ const jwtResponse = await descopeClient.saml.exchange('token');
178
+ // jwtResponse.data.sessionJwt;
179
+ // jwtResponse.data.refreshJwt;
180
+ ```
181
+
182
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
183
+
184
+ ### TOTP Authentication
185
+
186
+ The user can authenticate using an authenticator app, such as Google Authenticator.
187
+ Sign up like you would using any other authentication method. The sign up response
188
+ will then contain a QR code `image` that can be displayed to the user to scan using
189
+ their mobile device camera app, or the user can enter the `key` manually or click
190
+ on the link provided by the `provisioningURL`.
191
+
192
+ Existing users can add TOTP using the `update` function.
193
+
194
+ ```typescript
195
+ // Every user must have a login ID. All other user information is optional
196
+ const loginId = 'desmond@descope.com';
197
+ const user = {
198
+ name: 'Desmond Copland',
199
+ phone: '212-555-1234',
200
+ email: loginId,
201
+ };
202
+ const totpRes = await descopeClient.totp.signUp(loginId, user);
203
+ // Use one of the provided options to have the user add their credentials to the authenticator
204
+ totpRes.data.provisioningURL;
205
+ totpRes.data.image;
206
+ totpRes.data.key;
207
+ ```
208
+
209
+ There are 3 different ways to allow the user to save their credentials in
210
+ their authenticator app - either by clicking the provisioning URL, scanning the QR
211
+ image or inserting the key manually. After that, signing in is done using the code
212
+ the app produces.
213
+
214
+ ```typescript
215
+ const jwtResponse = await descopeClient.totp.verify(loginId, 'code');
216
+ // jwtResponse.data.sessionJwt;
217
+ // jwtResponse.data.refreshJwt;
218
+ ```
219
+
220
+ The session and refresh JWTs should be returned to the caller, and passed with every request in the session. Read more on [session validation](#session-validation)
221
+
222
+ ### Session Validation
223
+
224
+ Every secure request performed between your client and server needs to be validated. The client sends
225
+ the session and refresh tokens with every request, and they are validated using one of the following:
226
+
227
+ ```typescript
228
+ // Validate the session. Will throw if expired
229
+ const authInfo = await descopeClient.validateSession('sessionToken');
230
+
231
+ // If validateSession throws an exception, you will need to refresh the session using
232
+ const authInfo = await descopeClient.refreshSession('refreshToken');
233
+
234
+ // Alternatively, you could combine the two and
235
+ // have the session validated and automatically refreshed when expired
236
+ const authInfo = await descopeClient.validateAndRefreshSession('sessionToken', 'refreshToken');
237
+ ```
238
+
239
+ Choose the right session validation and refresh combination that suits your needs.
240
+ Refreshed sessions return the same response as is returned when users first sign up / log in,
241
+ containing the session and refresh tokens, as well as all of the JWT claims.
242
+ Make sure to return the session token from the response to the client if tokens are validated directly.
243
+
244
+ Usually, the tokens can be passed in and out via HTTP headers or via a cookie.
245
+ The implementation can defer according to your implementation. See our [examples](#code-examples) for a few examples.
246
+
247
+ If Roles & Permissions are used, validate them immediately after validating the session. See the [next section](#roles--permission-validation)
248
+ for more information.
249
+
250
+ #### Session Validation Using Middleware
251
+
252
+ Alternatively, you can create a simple middleware function that internally uses the `validateSession` function.
253
+ This middleware will automatically parse the cookies from the request.
254
+ On failure, it will respond with `401 Unauthorized`.
255
+
256
+ ```typescript
257
+ const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
258
+ try {
259
+ const cookies = parseCookies(req);
260
+ const out = await clientAuth.auth.validateSession(
261
+ cookies[DescopeClient.SessionTokenCookieName],
262
+ cookies[DescopeClient.RefreshTokenCookieName],
263
+ );
264
+ if (out?.cookies) {
265
+ res.set('Set-Cookie', out.cookies);
266
+ }
267
+ next();
268
+ } catch (e) {
269
+ res.status(401).json({
270
+ error: new Error('Unauthorized!'),
271
+ });
272
+ }
273
+ };
274
+ ```
275
+
276
+ ### Roles & Permission Validation
277
+
278
+ When using Roles & Permission, it's important to validate the user has the required
279
+ authorization immediately after making sure the session is valid. Taking the `AuthenticationInfo`
280
+ received by the [session validation](#session-validation), call the following functions:
281
+
282
+ For multi-tenant uses:
283
+
284
+ ```typescript
285
+ // You can validate specific permissions
286
+ const validTenantPermissions = await descopeClient.validateTenantPermissions(
287
+ authInfo,
288
+ 'my-tenant-ID',
289
+ ['Permission to validate'],
290
+ );
291
+ if (!validTenantPermissions) {
292
+ // Deny access
293
+ }
294
+
295
+ // Or validate roles directly
296
+ const validTenantRoles = await descopeClient.validateTenantRoles(authInfo, 'my-tenant-ID', [
297
+ 'Role to validate',
298
+ ]);
299
+ if (!validTenantRoles) {
300
+ // Deny access
301
+ }
302
+ ```
303
+
304
+ When not using tenants use:
305
+
306
+ ```typescript
307
+ // You can validate specific permissions
308
+ const validPermissions = await descopeClient.validatePermissions(authInfo, [
309
+ 'Permission to validate',
310
+ ]);
311
+ if (!validPermissions) {
312
+ // Deny access
313
+ }
314
+
315
+ // Or validate roles directly
316
+ const validRoles = await descopeClient.validateRoles(authInfo, ['Role to validate']);
317
+ if (!validRoles) {
318
+ // Deny access
319
+ }
320
+ ```
321
+
322
+ ### Logging Out
323
+
324
+ You can log out a user from an active session by providing their `refreshToken` for that session.
325
+ After calling this function, you must invalidate or remove any cookies you have created.
326
+
327
+ ```typescript
328
+ await descopeClient.logout(refreshToken);
329
+ ```
330
+
331
+ It is also possible to sign the user out of all the devices they are currently signed-in with. Calling `logoutAll` will
332
+ invalidate all user's refresh tokens. After calling this function, you must invalidate or remove any cookies you have created.
333
+
334
+ ```typescript
335
+ await descopeClient.logoutAll(refreshToken);
336
+ ```
337
+
338
+ ## Management API
339
+
340
+ It is very common for some form of management or automation to be required. These can be performed
341
+ using the management API. Please note that these actions are more sensitive as they are administrative
342
+ in nature. Please use responsibly.
343
+
344
+ ### Setup
345
+
346
+ To use the management API you'll need a `Management Key` along with your `Project ID`.
347
+ Create one in the [Descope Console](https://app.descope.com/settings/company/managementkeys).
348
+
349
+ ```typescript
350
+ import DescopeClient from '@descope/node-sdk';
351
+
352
+ const descopeClient = DescopeClient({
353
+ projectId: 'my-project-ID',
354
+ managementKey: 'management-key',
355
+ });
356
+ ```
357
+
358
+ ### Manage Tenants
359
+
360
+ You can create, update, delete or load tenants:
361
+
362
+ ```typescript
363
+ // The self provisioning domains or optional. If given they'll be used to associate
364
+ // Users logging in to this tenant
365
+ await descopeClient.management.tenant.create('My Tenant', ['domain.com']);
366
+
367
+ // You can optionally set your own ID when creating a tenant
368
+ await descopeClient.management.tenant.createWithId('my-custom-id', 'My Tenant', ['domain.com']);
369
+
370
+ // Update will override all fields as is. Use carefully.
371
+ await descopeClient.management.tenant.update('my-custom-id', 'My Tenant', [
372
+ 'domain.com',
373
+ 'another-domain.com',
374
+ ]);
375
+
376
+ // Tenant deletion cannot be undone. Use carefully.
377
+ await descopeClient.management.tenant.delete('my-custom-id');
378
+
379
+ // Load all tenants
380
+ const tenantsRes = await descopeClient.management.tenant.loadAll();
381
+ tenantsRes.data.forEach((tenant) => {
382
+ // do something
383
+ });
384
+ ```
385
+
386
+ ### Manage Users
387
+
388
+ You can create, update, delete or load users, as well as search according to filters:
389
+
390
+ ```typescript
391
+ // A user must have a login ID, other fields are optional.
392
+ // Roles should be set directly if no tenants exist, otherwise set
393
+ // on a per-tenant basis.
394
+ await descopeClient.management.user.create(
395
+ 'desmond@descope.com',
396
+ 'desmond@descope.com',
397
+ null,
398
+ 'Desmond Copeland',
399
+ null,
400
+ [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
401
+ );
402
+
403
+ // Update will override all fields as is. Use carefully.
404
+ await descopeClient.management.user.update(
405
+ 'desmond@descope.com',
406
+ 'desmond@descope.com',
407
+ null,
408
+ 'Desmond Copeland',
409
+ null,
410
+ [{ tenantId: 'tenant-ID1', roleNames: ['role-name1', 'role-name2'] }],
411
+ );
412
+
413
+ // Update explicit data for a user rather than overriding all fields
414
+ await descopeClient.management.user.updatePhone('desmond@descope.com', '+18005551234', true);
415
+ await descopeClient.management.user.removeTenantRoles(
416
+ 'desmond@descope.com',
417
+ 'tenant-ID1',
418
+ 'role-name2',
419
+ );
420
+
421
+ // User deletion cannot be undone. Use carefully.
422
+ await descopeClient.management.user.delete('desmond@descope.com');
423
+
424
+ // Load specific user
425
+ const userRes = await descopeClient.management.user.load('desmond@descope.com');
426
+
427
+ // If needed, users can be loaded using the user ID as well
428
+ const userRes = await descopeClient.management.user.loadByUserId('<user-ID>');
429
+
430
+ // Search all users, optionally according to tenant and/or role filter
431
+ const usersRes = await descopeClient.management.user.searchAll(['tenant-ID']);
432
+ usersRes.data.forEach((user) => {
433
+ // do something
434
+ });
435
+ ```
436
+
437
+ ### Manage Access Keys
438
+
439
+ You can create, update, delete or load access keys, as well as search according to filters:
440
+
441
+ ```typescript
442
+ // An access key must have a name and expiration, other fields are optional.
443
+ // Roles should be set directly if no tenants exist, otherwise set
444
+ // on a per-tenant basis.
445
+ await descopeClient.management.accessKey.create(
446
+ 'key-name',
447
+ 123456789, // expiration time
448
+ null,
449
+ [{ tenantId: 'tenant-ID1', roleNames: ['role-name1'] }],
450
+ );
451
+
452
+ // Load specific user
453
+ const accessKeyRes = await descopeClient.management.accessKey.load('key-id');
454
+
455
+ // Search all users, optionally according to tenant and/or role filter
456
+ const accessKeysRes = await descopeClient.management.accessKey.searchAll(['tenant-ID']);
457
+ accessKeysRes.data.forEach((accessKey) => {
458
+ // do something
459
+ });
460
+
461
+ // Update will override all fields as is. Use carefully.
462
+ await descopeClient.management.accessKey.update('key-id', 'new-key-name');
463
+
464
+ // Access keys can be deactivated to prevent usage. This can be undone using "activate".
465
+ await descopeClient.management.accessKey.deactivate('key-id');
466
+
467
+ // Disabled access keys can be activated once again.
468
+ await descopeClient.management.accessKey.activate('key-id');
469
+
470
+ // Access key deletion cannot be undone. Use carefully.
471
+ await descopeClient.management.accessKey.delete('key-id');
472
+ ```
473
+
474
+ ### Manage SSO Setting
475
+
476
+ You can manage SSO settings and map SSO group roles and user attributes.
477
+
478
+ ```typescript
479
+ // You can configure SSO settings manually by setting the required fields directly
480
+ const tenantId = 'tenant-id' // Which tenant this configuration is for
481
+ const idpURL = 'https://idp.com'
482
+ const entityID = 'my-idp-entity-id'
483
+ const idpCert = '<your-cert-here>'
484
+ const redirectURL = 'https://my-app.com/handle-saml' // Global redirect URL for SSO/SAML
485
+ const domain = 'tenant-users.com' // Users authentication with this domain will be logged in to this tenant
486
+ await descopeClient.management.sso.configureSettings(tenantID, idpURL, entityID, idpCert, redirectURL, domain)
487
+
488
+ // Alternatively, configure using an SSO metadata URL
489
+ await descopeClient.management.sso.configureMetadata(tenantID, 'https://idp.com/my-idp-metadata')
490
+
491
+ // Map IDP groups to Descope roles, or map user attributes.
492
+ // This function overrides any previous mapping (even when empty). Use carefully.
493
+ await descopeClient.management.sso.configureMapping(
494
+ tenantId,
495
+ { groups: ['IDP_ADMIN'], role: 'Tenant Admin'}
496
+ { name: 'IDP_NAME', phoneNumber: 'IDP_PHONE'},
497
+ )
498
+ ```
499
+
500
+ Note: Certificates should have a similar structure to:
16
501
 
17
- Click one of the following links to open the documentation for that specific functionality.
502
+ ```
503
+ -----BEGIN CERTIFICATE-----
504
+ Certifcate contents
505
+ -----END CERTIFICATE-----
506
+ ```
507
+
508
+ ### Manage Permissions
18
509
 
19
- - [x] [One time passwords (OTP)](./docs/otp.md)
20
- - [x] [Magic Links](./docs/magiclink.md)
21
- - [x] [OAuth/Social](./docs/oauth.md)
510
+ You can create, update, delete or load permissions:
22
511
 
23
- ## Run the Examples
512
+ ```typescript
513
+ // You can optionally set a description for a permission.
514
+ const name = 'My Permission';
515
+ let description = 'Optional description to briefly explain what this permission allows.';
516
+ await descopeClient.management.permission.create(name, description);
24
517
 
25
- Instantly run the end-to-end ExpresSDK for NodeJS examples, as shown below. The source code for these examples are in the folder [GitHub node-sdk/examples folder](https://github.com/descope/node-sdk/blob/main/examples).
518
+ // Update will override all fields as is. Use carefully.
519
+ const newName = 'My Updated Permission';
520
+ description = 'A revised description';
521
+ await descopeClient.management.permission.update(name, newName, description);
522
+
523
+ // Permission deletion cannot be undone. Use carefully.
524
+ await descopeClient.management.permission.delete(newName);
525
+
526
+ // Load all permissions
527
+ const permissionsRes = await descopeClient.management.permission.loadAll();
528
+ permissionsRes.data.forEach((permission) => {
529
+ // do something
530
+ });
531
+ ```
26
532
 
27
- ### Prerequisites
533
+ ### Manage Roles
28
534
 
29
- Run the following commands in your project. Replace any instance of `<ProjectID>` in the code below with your company's Project ID, which can be found in the [Descope console](https://app.descope.com).
535
+ You can create, update, delete or load roles:
536
+
537
+ ```typescript
538
+ // You can optionally set a description and associated permission for a roles.
539
+ const name = 'My Role';
540
+ let description = 'Optional description to briefly explain what this role allows.';
541
+ const permissionNames = ['My Updated Permission'];
542
+ descopeClient.management.role.create(name, description, permissionNames);
543
+
544
+ // Update will override all fields as is. Use carefully.
545
+ const newName = 'My Updated Role';
546
+ description = 'A revised description';
547
+ permissionNames.push('Another Permission');
548
+ descopeClient.management.role.update(name, newName, description, permissionNames);
549
+
550
+ // Role deletion cannot be undone. Use carefully.
551
+ descopeClient.management.role.delete(newName);
552
+
553
+ // Load all roles
554
+ const rolesRes = await descopeClient.management.role.loadAll();
555
+ rolesRes.data.forEach((role) => {
556
+ // do something
557
+ });
558
+ ```
30
559
 
31
- This commands will add the Descope NodeJS SDK as a project dependency, clone the SDK repository locally, and set the `DESCOPE_PROJECT_ID`.
560
+ ### Query SSO Groups
32
561
 
33
- ```code bash
34
- git clone github.com/descope/node-sdk
562
+ You can query SSO groups:
563
+
564
+ ```typescript
565
+ // Load all groups for a given tenant id
566
+ const groupsRes = descopeClient.management.group.loadAllGroups('tenant-id');
567
+
568
+ // Load all groups for the given user IDs (can be found in the user's JWT)
569
+ const groupsRes = descopeClient.management.group.loadAllGroupsForMember('tenant-id', [
570
+ 'user-id-1',
571
+ 'user-id-2',
572
+ ]);
573
+
574
+ // Load all groups for the given user login IDs (used for sign-in)
575
+ const groupsRes = descopeClient.management.group.loadAllGroupsForMember(
576
+ 'tenant-id',
577
+ [],
578
+ ['login-id-1', 'login-id-2'],
579
+ );
580
+
581
+ // Load all group's members by the given group id
582
+ const groupsRes = descopeClient.management.group.loadAllGroupMembers('tenant-id', 'group-id');
583
+
584
+ groupsRes.data.forEach((group) => {
585
+ // do something
586
+ });
587
+ ```
588
+
589
+ ### Manage JWTs
590
+
591
+ You can add custom claims to a valid JWT.
592
+
593
+ ```typescript
594
+ const updatedJWTRes = await descopeClient.management.jwt.update('original-jwt', {
595
+ customKey1: 'custom-value1',
596
+ customKey2: 'custom-value2',
597
+ });
598
+ ```
599
+
600
+ ## Code Examples
601
+
602
+ You can find various usage examples in the [examples folder](https://github.com/descope/node-sdk/blob/main/examples).
603
+
604
+ ### Setup
605
+
606
+ To run the examples, set your `Project ID` by setting the `DESCOPE_PROJECT_ID` env var or directly
607
+ in the sample code.
608
+ Find your Project ID in the [Descope console](https://app.descope.com/settings/project).
609
+
610
+ ```bash
35
611
  export DESCOPE_PROJECT_ID=<ProjectID>
36
612
  ```
37
613
 
38
614
  ### Run an example
39
615
 
40
- **TL;DR**: Run `npm run quick`
41
-
42
- Run the following commands in the root of the project to build and run the examples.
616
+ Run the following commands in the root of the project to build and run the examples with a local build
617
+ of the SDK.
43
618
 
44
619
  1. Run this to start the ES6 typescript module example
45
620
 
46
- ```code bash
621
+ ```bash
47
622
  npm i && \
48
623
  npm run build && \
49
624
  cd examples/es6 && \
@@ -54,7 +629,7 @@ Run the following commands in the root of the project to build and run the examp
54
629
 
55
630
  2. Run this to start the commonjs example
56
631
 
57
- ```code bash
632
+ ```bash
58
633
  npm i && \
59
634
  npm run build && \
60
635
  cd examples/commonjs && \
@@ -63,6 +638,14 @@ Run the following commands in the root of the project to build and run the examp
63
638
  npm start
64
639
  ```
65
640
 
641
+ ## Learn More
642
+
643
+ To learn more please see the [Descope Documentation and API reference page](https://docs.descope.com/).
644
+
645
+ ## Contact Us
646
+
647
+ If you need help you can email [Descope Support](mailto:support@descope.com)
648
+
66
649
  ## License
67
650
 
68
- The Descope ExpresSDK for Node is licensed for use under the terms and conditions of the [MIT license Agreement](https://github.com/descope/node-sdk/blob/main/LICENSE).
651
+ The Descope SDK for Node.js is licensed for use under the terms and conditions of the [MIT license Agreement](https://github.com/descope/node-sdk/blob/main/LICENSE).