@or-sdk/authorizer 0.10.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.
Files changed (112) hide show
  1. package/dist/cjs/Basic/BasicAuth.js +157 -0
  2. package/dist/cjs/Basic/BasicAuth.js.map +1 -0
  3. package/dist/cjs/Basic/BasicCollection.js +107 -0
  4. package/dist/cjs/Basic/BasicCollection.js.map +1 -0
  5. package/dist/cjs/Basic/types.js +3 -0
  6. package/dist/cjs/Basic/types.js.map +1 -0
  7. package/dist/cjs/Basic/utils/createAuthKey.js +8 -0
  8. package/dist/cjs/Basic/utils/createAuthKey.js.map +1 -0
  9. package/dist/cjs/OAuth/OAuth.js +391 -0
  10. package/dist/cjs/OAuth/OAuth.js.map +1 -0
  11. package/dist/cjs/OAuth/OAuthCollection.js +138 -0
  12. package/dist/cjs/OAuth/OAuthCollection.js.map +1 -0
  13. package/dist/cjs/OAuth/types.js +11 -0
  14. package/dist/cjs/OAuth/types.js.map +1 -0
  15. package/dist/cjs/OAuth/utils/ServiceDefinition.js +175 -0
  16. package/dist/cjs/OAuth/utils/ServiceDefinition.js.map +1 -0
  17. package/dist/cjs/OAuth/utils/createAuthKey.js +8 -0
  18. package/dist/cjs/OAuth/utils/createAuthKey.js.map +1 -0
  19. package/dist/cjs/OAuth/utils/formatScope.js +20 -0
  20. package/dist/cjs/OAuth/utils/formatScope.js.map +1 -0
  21. package/dist/cjs/OAuth/utils/isExpired.js +12 -0
  22. package/dist/cjs/OAuth/utils/isExpired.js.map +1 -0
  23. package/dist/cjs/Token/TokenAuth.js +135 -0
  24. package/dist/cjs/Token/TokenAuth.js.map +1 -0
  25. package/dist/cjs/Token/TokenCollection.js +106 -0
  26. package/dist/cjs/Token/TokenCollection.js.map +1 -0
  27. package/dist/cjs/Token/types.js +3 -0
  28. package/dist/cjs/Token/types.js.map +1 -0
  29. package/dist/cjs/Token/utils/createAuthKey.js +8 -0
  30. package/dist/cjs/Token/utils/createAuthKey.js.map +1 -0
  31. package/dist/cjs/constants.js +16 -0
  32. package/dist/cjs/constants.js.map +1 -0
  33. package/dist/cjs/index.js +27 -0
  34. package/dist/cjs/index.js.map +1 -0
  35. package/dist/cjs/types.js +16 -0
  36. package/dist/cjs/types.js.map +1 -0
  37. package/dist/esm/Basic/BasicAuth.js +86 -0
  38. package/dist/esm/Basic/BasicAuth.js.map +1 -0
  39. package/dist/esm/Basic/BasicCollection.js +56 -0
  40. package/dist/esm/Basic/BasicCollection.js.map +1 -0
  41. package/dist/esm/Basic/types.js +2 -0
  42. package/dist/esm/Basic/types.js.map +1 -0
  43. package/dist/esm/Basic/utils/createAuthKey.js +4 -0
  44. package/dist/esm/Basic/utils/createAuthKey.js.map +1 -0
  45. package/dist/esm/OAuth/OAuth.js +258 -0
  46. package/dist/esm/OAuth/OAuth.js.map +1 -0
  47. package/dist/esm/OAuth/OAuthCollection.js +69 -0
  48. package/dist/esm/OAuth/OAuthCollection.js.map +1 -0
  49. package/dist/esm/OAuth/types.js +8 -0
  50. package/dist/esm/OAuth/types.js.map +1 -0
  51. package/dist/esm/OAuth/utils/ServiceDefinition.js +117 -0
  52. package/dist/esm/OAuth/utils/ServiceDefinition.js.map +1 -0
  53. package/dist/esm/OAuth/utils/createAuthKey.js +4 -0
  54. package/dist/esm/OAuth/utils/createAuthKey.js.map +1 -0
  55. package/dist/esm/OAuth/utils/formatScope.js +16 -0
  56. package/dist/esm/OAuth/utils/formatScope.js.map +1 -0
  57. package/dist/esm/OAuth/utils/isExpired.js +8 -0
  58. package/dist/esm/OAuth/utils/isExpired.js.map +1 -0
  59. package/dist/esm/Token/TokenAuth.js +64 -0
  60. package/dist/esm/Token/TokenAuth.js.map +1 -0
  61. package/dist/esm/Token/TokenCollection.js +55 -0
  62. package/dist/esm/Token/TokenCollection.js.map +1 -0
  63. package/dist/esm/Token/types.js +2 -0
  64. package/dist/esm/Token/types.js.map +1 -0
  65. package/dist/esm/Token/utils/createAuthKey.js +4 -0
  66. package/dist/esm/Token/utils/createAuthKey.js.map +1 -0
  67. package/dist/esm/constants.js +13 -0
  68. package/dist/esm/constants.js.map +1 -0
  69. package/dist/esm/index.js +8 -0
  70. package/dist/esm/index.js.map +1 -0
  71. package/dist/esm/types.js +4 -0
  72. package/dist/esm/types.js.map +1 -0
  73. package/dist/types/Basic/BasicAuth.d.ts +19 -0
  74. package/dist/types/Basic/BasicCollection.d.ts +12 -0
  75. package/dist/types/Basic/types.d.ts +26 -0
  76. package/dist/types/Basic/utils/createAuthKey.d.ts +1 -0
  77. package/dist/types/OAuth/OAuth.d.ts +18 -0
  78. package/dist/types/OAuth/OAuthCollection.d.ts +14 -0
  79. package/dist/types/OAuth/types.d.ts +81 -0
  80. package/dist/types/OAuth/utils/ServiceDefinition.d.ts +36 -0
  81. package/dist/types/OAuth/utils/createAuthKey.d.ts +1 -0
  82. package/dist/types/OAuth/utils/formatScope.d.ts +2 -0
  83. package/dist/types/OAuth/utils/isExpired.d.ts +1 -0
  84. package/dist/types/Token/TokenAuth.d.ts +11 -0
  85. package/dist/types/Token/TokenCollection.d.ts +12 -0
  86. package/dist/types/Token/types.d.ts +25 -0
  87. package/dist/types/Token/utils/createAuthKey.d.ts +1 -0
  88. package/dist/types/constants.d.ts +11 -0
  89. package/dist/types/index.d.ts +7 -0
  90. package/dist/types/types.d.ts +3 -0
  91. package/package.json +33 -0
  92. package/src/Basic/BasicAuth.ts +147 -0
  93. package/src/Basic/BasicCollection.ts +97 -0
  94. package/src/Basic/types.ts +54 -0
  95. package/src/Basic/utils/createAuthKey.ts +3 -0
  96. package/src/OAuth/OAuth.ts +480 -0
  97. package/src/OAuth/OAuthCollection.ts +138 -0
  98. package/src/OAuth/types.ts +131 -0
  99. package/src/OAuth/utils/ServiceDefinition.ts +171 -0
  100. package/src/OAuth/utils/createAuthKey.ts +3 -0
  101. package/src/OAuth/utils/formatScope.ts +20 -0
  102. package/src/OAuth/utils/isExpired.ts +7 -0
  103. package/src/Token/TokenAuth.ts +120 -0
  104. package/src/Token/TokenCollection.ts +97 -0
  105. package/src/Token/types.ts +51 -0
  106. package/src/Token/utils/createAuthKey.ts +3 -0
  107. package/src/constants.ts +14 -0
  108. package/src/index.ts +10 -0
  109. package/src/types.ts +3 -0
  110. package/tsconfig.esm.json +9 -0
  111. package/tsconfig.json +7 -0
  112. package/tsconfig.types.json +9 -0
@@ -0,0 +1,480 @@
1
+ import { KeyValueStorage } from '@or-sdk/key-value-storage';
2
+ import { EventManager } from '@or-sdk/event-manager';
3
+ import { timeout } from '@or-sdk/base';
4
+
5
+ import { v4 as uuidv4 } from 'uuid';
6
+
7
+ import {
8
+ OAuthConfig,
9
+ OAuthData,
10
+ OAuthApp,
11
+ CreateOAuthConfig,
12
+ CreateOAuthResult,
13
+ ServiceDefinitionConfig,
14
+ } from './types';
15
+
16
+ import {
17
+ SERVICE_PROVIDER_PATH,
18
+ OAUTH_REDIRECT_PROVIDER_PATH,
19
+ PREDEFINED_APP,
20
+ TEMPORARY_DATA_EXPIRATION_TIME,
21
+ AuthStatus,
22
+ } from '../constants';
23
+
24
+ import { formatScope } from './utils/formatScope';
25
+ import { isExpired } from './utils/isExpired';
26
+ import { ServiceDefinition } from './utils/ServiceDefinition';
27
+ import { createAuthKey } from './utils/createAuthKey';
28
+
29
+ /**
30
+ * OneReach Authorizer service client
31
+ * ## Installation:
32
+ * ```
33
+ * $ npm i @or-sdk/authorizer
34
+ * ```
35
+ */
36
+ export class OAuth {
37
+ private status = AuthStatus.READY;
38
+
39
+ private readonly authKey: string;
40
+ private readonly serviceName: string;
41
+ private readonly keyValueCollection: string;
42
+ private readonly keyValueStorage: KeyValueStorage;
43
+ private readonly eventManager: EventManager;
44
+
45
+ /**
46
+ * Connects to existing authorization
47
+ *
48
+ * ```typescript
49
+ * import { OAuth } from '@or-sdk/authorizer'
50
+ * const oAuthInstance = new OAuth({
51
+ * token: 'my-account-token-string',
52
+ * discoveryUrl: 'discovery.example.onereach.ai',
53
+ * serviceName: '__authorization_service_test_service',
54
+ * authKey: '637ac446-1021-475f-9992-3ce7f3ddb637::oauth::someAuth::__authorization_service_test_service::02bf4366-f987-49ea-90a6-0d346e13c3c1',
55
+ * keyValueCollection: 'custom_collection_name' // Pass this if you using custom name for key-value collection that differs from serviceName
56
+ * });
57
+ * ```
58
+ */
59
+ constructor(params: OAuthConfig) {
60
+ const { token, discoveryUrl, authKey, serviceName, keyValueCollection } =
61
+ params;
62
+
63
+ this.authKey = authKey;
64
+ this.serviceName = serviceName;
65
+ this.keyValueCollection = keyValueCollection || serviceName;
66
+
67
+ this.keyValueStorage = new KeyValueStorage({
68
+ token,
69
+ discoveryUrl,
70
+ });
71
+
72
+ this.eventManager = new EventManager({
73
+ token,
74
+ discoveryUrl,
75
+ requestAccountId: true,
76
+ requestProvidersAccountId: true,
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Creates a new auth record in specified collection with the given config.
82
+ * @returns Object with OAuth instance connected to created auth and authorizerUrl to redirect the user to for completing authorization
83
+ *
84
+ * ```typescript
85
+ * const {
86
+ * authorizeUrl, // redirect user to this url for completing authorization
87
+ * instance // new instance
88
+ * } = await OAuth.create({
89
+ * token: 'my-account-token-string',
90
+ * discoveryUrl: 'discovery.example.onereach.ai',
91
+ * serviceName: '__authorization_service_test_service',
92
+ * authName: 'my-auth-name',
93
+ * appId: 'my-app-id',
94
+ * keyValueCollection: 'custom_collection_name' // Pass this if you using custom name for key-value collection that differs from serviceName
95
+ * });
96
+ *
97
+ * // if you want to use returned instance, you must call a method that returns a promise that will be resolved when the user completes authorization process
98
+ * // if not, you can omit this step
99
+ * try {
100
+ * await instance.waitForCompletion()
101
+ * } catch (e) {
102
+ * // will be called if the user does not complete authorization within 5 minutes
103
+ * }
104
+ * ```
105
+ */
106
+ static async create(
107
+ params: CreateOAuthConfig
108
+ ): Promise<CreateOAuthResult> {
109
+ if (
110
+ !(
111
+ params.serviceName &&
112
+ params.authName &&
113
+ params.discoveryUrl &&
114
+ params.token &&
115
+ params.appId
116
+ )
117
+ ) {
118
+ throw new Error('Invalid config passed');
119
+ }
120
+
121
+ const { serviceName, authName, discoveryUrl, token, appId, scope } = params;
122
+
123
+ const keyValueCollection = params.keyValueCollection || serviceName;
124
+
125
+ const keyValueStorage = new KeyValueStorage({
126
+ token,
127
+ discoveryUrl,
128
+ });
129
+
130
+ const eventManager = new EventManager({
131
+ token,
132
+ discoveryUrl,
133
+ requestAccountId: true,
134
+ requestProvidersAccountId: true,
135
+ });
136
+
137
+ await eventManager.init();
138
+
139
+ const serviceDefinitionProviderRoute = `http/${eventManager.providersAccountId}${SERVICE_PROVIDER_PATH}`;
140
+
141
+ const services = await eventManager.makeRequest<{
142
+ [key: string]: ServiceDefinitionConfig;
143
+ }>({
144
+ method: 'GET',
145
+ route: serviceDefinitionProviderRoute,
146
+ params: {
147
+ type: 'list',
148
+ },
149
+ });
150
+
151
+ const currentServiceData = services[serviceName];
152
+
153
+ const apps = await keyValueStorage.getValueByKey(
154
+ keyValueCollection,
155
+ '__authorizer_apps'
156
+ );
157
+
158
+ const currentApp: OAuthApp = (apps.value as any).find(
159
+ (app: { label: string; value: OAuthApp; }) => app.value.appId === appId
160
+ ).value;
161
+
162
+ const serviceDefinition = new ServiceDefinition(
163
+ currentServiceData,
164
+ currentApp.authLinkParams,
165
+ currentApp.environment
166
+ );
167
+
168
+ const id = uuidv4();
169
+ const authKey = createAuthKey(id, authName, keyValueCollection, eventManager.currentAccountId);
170
+
171
+ const additionalBodyData = {};
172
+ const additionalHeaders = {};
173
+
174
+ const emUrl = eventManager.serviceUrl;
175
+ const redirectProviderUrl = `${emUrl}/http/${eventManager.providersAccountId}${OAUTH_REDIRECT_PROVIDER_PATH}`;
176
+
177
+ const authConfigs: any = {
178
+ ...additionalBodyData,
179
+ grant_type: 'authorization_code',
180
+ redirect_uri: redirectProviderUrl,
181
+ appId,
182
+ };
183
+
184
+ if (scope) {
185
+ const formattedScope = formatScope(scope, serviceDefinition.scopeType);
186
+ authConfigs.scope = formattedScope;
187
+ }
188
+
189
+ const configs = {
190
+ [serviceDefinition.requestDataType]: authConfigs,
191
+ };
192
+
193
+ const tempAuthData = {
194
+ expiresInDefaultValue: serviceDefinition.expiresInDefaultValue,
195
+ urlToExchangeToken: serviceDefinition.exchangeTokenUri,
196
+ refreshUri: serviceDefinition.refreshUri,
197
+ additionalHeaders,
198
+ configs,
199
+ isCustomApp: appId !== PREDEFINED_APP,
200
+ requestDataType: serviceDefinition.requestDataType,
201
+ service: keyValueCollection,
202
+ serviceConfigName: serviceName,
203
+ name: authName,
204
+ displayServiceName: serviceDefinition.displayServiceName,
205
+ accountId: eventManager.currentAccountId,
206
+ };
207
+
208
+ const authDataExpire = Date.now() + TEMPORARY_DATA_EXPIRATION_TIME;
209
+ await keyValueStorage.setValueByKey(
210
+ '__authorizer_temp-uuid',
211
+ id,
212
+ tempAuthData,
213
+ authDataExpire
214
+ );
215
+
216
+ const authUrl = new URL(serviceDefinition.authorizeUri);
217
+ const additionalParams: { [key: string]: string; } = JSON.parse(
218
+ serviceDefinition.authRequestAdditionalParams
219
+ );
220
+
221
+ Object.entries(additionalParams.queryParams).forEach(([key, value]) => {
222
+ authUrl.searchParams.append(key, value);
223
+ });
224
+ authUrl.searchParams.append('response_type', 'code');
225
+ authUrl.searchParams.append('client_id', currentApp.clientId);
226
+ authUrl.searchParams.append('redirect_uri', redirectProviderUrl);
227
+ authUrl.searchParams.append('state', authKey);
228
+
229
+ if (scope) {
230
+ const formattedScope = formatScope(scope, serviceDefinition.scopeType);
231
+ authUrl.searchParams.append('scope', formattedScope);
232
+ }
233
+
234
+ const authorizeUrl = authUrl.href;
235
+
236
+ const newOAuth = new OAuth({
237
+ serviceName,
238
+ authKey,
239
+ discoveryUrl,
240
+ token,
241
+ });
242
+
243
+ newOAuth.status = AuthStatus.PENDING;
244
+
245
+ return {
246
+ instance: newOAuth,
247
+ authorizeUrl,
248
+ };
249
+ }
250
+
251
+ private async getOAuthAppById(appId: string): Promise<OAuthApp | undefined> {
252
+ const appsStorageRecord = await this.keyValueStorage.getValueByKey(
253
+ this.keyValueCollection,
254
+ '__authorizer_apps'
255
+ );
256
+
257
+ const appsRecords = appsStorageRecord.value as Array<{
258
+ label: string;
259
+ value: Omit<OAuthApp, 'name'>;
260
+ }>;
261
+
262
+ const currentApp = appsRecords.find(app => app.value.appId === appId);
263
+
264
+ if (!currentApp) {
265
+ return;
266
+ }
267
+
268
+ return {
269
+ name: currentApp.label,
270
+ ...currentApp.value,
271
+ };
272
+ }
273
+
274
+ private async getServiceDefinition(currentApp: OAuthApp): Promise<ServiceDefinition> {
275
+ await this.eventManager.init();
276
+
277
+ const serviceDefinitionProviderRoute = `http/${this.eventManager.providersAccountId}${SERVICE_PROVIDER_PATH}`;
278
+
279
+ const services = await this.eventManager.makeRequest<{
280
+ [key: string]: ServiceDefinitionConfig;
281
+ }>({
282
+ method: 'GET',
283
+ route: serviceDefinitionProviderRoute,
284
+ params: {
285
+ type: 'list',
286
+ },
287
+ });
288
+
289
+ const currentServiceData = services[this.serviceName];
290
+
291
+ return new ServiceDefinition(
292
+ currentServiceData,
293
+ currentApp.authLinkParams,
294
+ currentApp.environment
295
+ );
296
+ }
297
+
298
+ /**
299
+ * Returns a promise that will be resolved after the user completes the authorization process
300
+ *
301
+ * ```typescript
302
+ * instance.waitForCompletion()
303
+ * .then(() => {
304
+ * // will be called after the user completes the authorization process
305
+ * })
306
+ * .catch(() => {
307
+ * // will be called if the user does not complete authorization within 5 minutes
308
+ * })
309
+ * ```
310
+ */
311
+ public async waitForCompletion(): Promise<void> {
312
+ if (this.status === AuthStatus.PENDING) {
313
+ let pollInterval = 3;
314
+ const step = 1;
315
+ const pollTimeout = 300; // 5 minutes
316
+
317
+ let spentTime = 0;
318
+ let isFinished = false;
319
+
320
+ while (spentTime < pollTimeout) {
321
+ const record = await this.keyValueStorage.getValueByKey(
322
+ this.keyValueCollection,
323
+ this.authKey
324
+ );
325
+
326
+ if (record.value) {
327
+ isFinished = true;
328
+ break;
329
+ }
330
+
331
+ await timeout(pollInterval);
332
+ spentTime += pollInterval;
333
+ pollInterval += step;
334
+ }
335
+
336
+ if (!isFinished) {
337
+ this.status = AuthStatus.ERROR;
338
+ throw new Error(
339
+ 'Authorization was not completed within the allowed time'
340
+ );
341
+ }
342
+ }
343
+
344
+ this.status = AuthStatus.READY;
345
+ }
346
+
347
+ /**
348
+ * Returns authorization data and performs refresh token request if needed
349
+ *
350
+ * ```typescript
351
+ * const authData = await oAuthInstance.getAuthData()
352
+ * ```
353
+ */
354
+ public async getAuthData(): Promise<OAuthData> {
355
+ if (this.status !== AuthStatus.READY) {
356
+ throw new Error('This authorization is not ready');
357
+ }
358
+
359
+ const { value } = await this.keyValueStorage.getValueByKey(
360
+ this.serviceName,
361
+ this.authKey
362
+ );
363
+
364
+ if (!value) {
365
+ this.status = AuthStatus.ERROR;
366
+ throw new Error('Authorization record does not exist');
367
+ }
368
+
369
+ const authData = value as OAuthData;
370
+
371
+ if (!authData.expires_in) {
372
+ return authData;
373
+ }
374
+
375
+ const expired = isExpired(authData.created_at, authData.expires_in);
376
+
377
+ if (!expired) {
378
+ return authData;
379
+ }
380
+
381
+ await this.refresh();
382
+
383
+ const { value: refreshedAuthData } =
384
+ await this.keyValueStorage.getValueByKey(this.serviceName, this.authKey);
385
+
386
+ return refreshedAuthData as OAuthData;
387
+ }
388
+
389
+ /**
390
+ * Perform token request manually
391
+ */
392
+ public async refresh(): Promise<void> {
393
+ const { value } = await this.keyValueStorage.getValueByKey(
394
+ this.serviceName,
395
+ this.authKey
396
+ );
397
+
398
+ if (!value) {
399
+ this.status = AuthStatus.ERROR;
400
+ throw new Error('Authorization record does not exist');
401
+ }
402
+
403
+ const authData = value as OAuthData;
404
+
405
+ const appId = authData.appId;
406
+
407
+ const currentApp = await this.getOAuthAppById(appId);
408
+
409
+ if (!currentApp) {
410
+ this.status = AuthStatus.ERROR;
411
+ throw new Error('The application used for this authorization does not exist');
412
+ }
413
+
414
+ const serviceDefinition = await this.getServiceDefinition(currentApp);
415
+
416
+ await this.eventManager.makeRequest({
417
+ method: 'POST',
418
+ route: new URL(authData.redirect_uri).pathname,
419
+ data: {
420
+ refreshTokenUrl: authData.refreshUri,
421
+ sendDataType: serviceDefinition.requestDataType,
422
+ currentUserData: authData,
423
+ service: this.keyValueCollection,
424
+ currentAuth: this.authKey,
425
+ },
426
+ });
427
+ }
428
+
429
+ /**
430
+ * Returns a OAuth app which is using in this authorization
431
+ *
432
+ * ```typescript
433
+ * const oAuthApp = await oAuthInstance.getOAuthApp()
434
+ * ```
435
+ */
436
+ public async getOAuthApp(): Promise<OAuthApp> {
437
+ if (this.status !== AuthStatus.READY) {
438
+ throw new Error('This authorization is not ready');
439
+ }
440
+
441
+ const { value } = await this.keyValueStorage.getValueByKey(
442
+ this.serviceName,
443
+ this.authKey
444
+ );
445
+
446
+ if (!value) {
447
+ this.status = AuthStatus.ERROR;
448
+ throw new Error('Authorization record does not exist');
449
+ }
450
+
451
+ const authData = value as OAuthData;
452
+
453
+ const appId = authData.appId;
454
+
455
+ const currentApp = await this.getOAuthAppById(appId);
456
+
457
+ if (!currentApp) {
458
+ this.status = AuthStatus.ERROR;
459
+ throw new Error('The application used for this authorization does not exist');
460
+ }
461
+
462
+ return currentApp;
463
+ }
464
+
465
+ /**
466
+ * Deletes authorization from collection
467
+ *
468
+ * ```typescript
469
+ * await oAuthInstance.delete()
470
+ * ```
471
+ */
472
+ public async delete(): Promise<void> {
473
+ await this.keyValueStorage.deleteKey(
474
+ this.serviceName,
475
+ this.authKey
476
+ );
477
+
478
+ this.status = AuthStatus.DELETED;
479
+ }
480
+ }
@@ -0,0 +1,138 @@
1
+ import { Token } from '@or-sdk/base';
2
+ import { KeyValueStorage } from '@or-sdk/key-value-storage';
3
+ import { OAuth } from './OAuth';
4
+
5
+ import { OAuthCollectionConfig, CreateOAuthInCollectionConfig, CreateOAuthResult, OAuthApp } from './types';
6
+
7
+ /**
8
+ * OneReach Authorizer service client
9
+ * ## Installation:
10
+ * ```
11
+ * $ npm i @or-sdk/authorizer
12
+ * ```
13
+ */
14
+ export class OAuthCollection {
15
+ private readonly serviceName: string;
16
+ private readonly keyValueCollection: string;
17
+ private readonly keyValueStorage: KeyValueStorage;
18
+ private readonly localToken: Token;
19
+ private readonly localDiscoveryUrl: string;
20
+
21
+ /**
22
+ * Connects to authorization collection
23
+ *
24
+ * ```typescript
25
+ * import { OAuthCollection } from '@or-sdk/authorizer'
26
+ * const oAuthCollectionInstance = new OAuthCollection({
27
+ * token: 'my-account-token-string',
28
+ * discoveryUrl: 'discovery.example.onereach.ai',
29
+ * serviceName: '__authorization_service_test_service',
30
+ * keyValueCollections: 'custom-collection-name' // Pass this if you using custom name for key-value collection that differs from serviceName
31
+ * });
32
+ * ```
33
+ */
34
+ constructor(params: OAuthCollectionConfig) {
35
+ const { token, discoveryUrl, serviceName, keyValueCollection } = params;
36
+
37
+ this.localToken = token;
38
+ this.localDiscoveryUrl = discoveryUrl;
39
+ this.serviceName = serviceName;
40
+ this.keyValueCollection = keyValueCollection || serviceName;
41
+ this.keyValueStorage = new KeyValueStorage({
42
+ token,
43
+ discoveryUrl,
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Returns array of auth keys from this collection
49
+ */
50
+ public async listAuthorizations(): Promise<string[]> {
51
+ const records = await this.keyValueStorage.listKeys(
52
+ this.keyValueCollection
53
+ );
54
+
55
+ return records.map((record) => record.key);
56
+ }
57
+
58
+ /**
59
+ * Returns array of OAuth applications for this service
60
+ */
61
+ public async listOAuthApps(): Promise<OAuthApp[]> {
62
+ const appsStorageRecord = await this.keyValueStorage.getValueByKey(
63
+ this.keyValueCollection,
64
+ '__authorizer_apps'
65
+ );
66
+
67
+ if (!appsStorageRecord.value) {
68
+ return [];
69
+ }
70
+
71
+ const appsRecords = appsStorageRecord.value as Array<{
72
+ label: string;
73
+ value: Omit<OAuthApp, 'name'>;
74
+ }>;
75
+
76
+ return appsRecords.map((record) => ({
77
+ name: record.label,
78
+ ...record.value,
79
+ }));
80
+ }
81
+
82
+ /**
83
+ * Returns OAuth instance for given key
84
+ */
85
+ public async getAuthorization(key: string): Promise<OAuth> {
86
+ const record = await this.keyValueStorage.getValueByKey(
87
+ this.keyValueCollection,
88
+ key
89
+ );
90
+ if (!record.value) {
91
+ throw new Error('This authorization does not exist');
92
+ }
93
+
94
+ return new OAuth({
95
+ serviceName: this.serviceName,
96
+ keyValueCollection: this.keyValueCollection,
97
+ authKey: key,
98
+ discoveryUrl: this.localDiscoveryUrl,
99
+ token: this.localToken,
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Creates a new auth record in current collection with the given config.
105
+ * @returns Object with OAuth instance connected to created auth and authorizerUrl to redirect the user to for completing authorization
106
+ *
107
+ * ```typescript
108
+ * const {
109
+ * authorizeUrl, // redirect user to this url for completing authorization
110
+ * instance // new instance
111
+ * } = await oAuthCollectionInstance.createAuthorization({
112
+ * authName: 'my-auth-name',
113
+ * appId: 'my-app-id',
114
+ * });
115
+ *
116
+ * // if you want to use returned instance, you must call a method that returns a promise that will be resolved when the user completes authorization process
117
+ * // if not, you can omit this step
118
+ * try {
119
+ * await instance.waitForCompletion()
120
+ * } catch (e) {
121
+ * // will be called if the user does not complete authorization within 5 minutes
122
+ * }
123
+ * ```
124
+ */
125
+ public async createAuthorization(
126
+ params: CreateOAuthInCollectionConfig,
127
+ ): Promise<CreateOAuthResult> {
128
+ return await OAuth.create({
129
+ discoveryUrl: this.localDiscoveryUrl,
130
+ token: this.localToken,
131
+ appId: params.appId,
132
+ keyValueCollection: this.keyValueCollection,
133
+ scope: params.scope,
134
+ serviceName: this.serviceName,
135
+ authName: params.authName,
136
+ });
137
+ }
138
+ }