@or-sdk/authorizer 0.25.0-beta.990.0 → 0.25.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 (109) hide show
  1. package/CHANGELOG.md +317 -0
  2. package/README.md +12 -32
  3. package/dist/cjs/Basic/BasicCollection.js +166 -26
  4. package/dist/cjs/Basic/BasicCollection.js.map +1 -1
  5. package/dist/cjs/Basic/utils/createAuthKey.js +4 -0
  6. package/dist/cjs/Basic/utils/createAuthKey.js.map +1 -1
  7. package/dist/cjs/OAuth/OAuth.js +92 -138
  8. package/dist/cjs/OAuth/OAuth.js.map +1 -1
  9. package/dist/cjs/OAuth/index.js +1 -3
  10. package/dist/cjs/OAuth/index.js.map +1 -1
  11. package/dist/cjs/OAuth/types.js +1 -1
  12. package/dist/cjs/OAuth/types.js.map +1 -1
  13. package/dist/cjs/OAuth/utils/ServiceDefinition.js.map +1 -1
  14. package/dist/cjs/OAuth/utils/createAuthKey.js +4 -0
  15. package/dist/cjs/OAuth/utils/createAuthKey.js.map +1 -1
  16. package/dist/cjs/OAuth/utils/createOAuthHelper.js +379 -0
  17. package/dist/cjs/OAuth/utils/createOAuthHelper.js.map +1 -0
  18. package/dist/cjs/OAuth/utils/formatScope.js.map +1 -1
  19. package/dist/cjs/{OAuth → OAuthCollection}/OAuthCollection.js +132 -28
  20. package/dist/cjs/OAuthCollection/OAuthCollection.js.map +1 -0
  21. package/dist/cjs/OAuthCollection/index.js +21 -0
  22. package/dist/cjs/OAuthCollection/index.js.map +1 -0
  23. package/dist/cjs/Token/TokenCollection.js +166 -21
  24. package/dist/cjs/Token/TokenCollection.js.map +1 -1
  25. package/dist/cjs/Token/utils/createAuthKey.js +4 -0
  26. package/dist/cjs/Token/utils/createAuthKey.js.map +1 -1
  27. package/dist/cjs/constants.js +3 -2
  28. package/dist/cjs/constants.js.map +1 -1
  29. package/dist/cjs/index.js +2 -1
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/esm/Basic/BasicCollection.js +115 -17
  32. package/dist/esm/Basic/BasicCollection.js.map +1 -1
  33. package/dist/esm/Basic/utils/createAuthKey.js +3 -0
  34. package/dist/esm/Basic/utils/createAuthKey.js.map +1 -1
  35. package/dist/esm/OAuth/OAuth.js +56 -115
  36. package/dist/esm/OAuth/OAuth.js.map +1 -1
  37. package/dist/esm/OAuth/index.js +0 -1
  38. package/dist/esm/OAuth/index.js.map +1 -1
  39. package/dist/esm/OAuth/types.js.map +1 -1
  40. package/dist/esm/OAuth/utils/ServiceDefinition.js.map +1 -1
  41. package/dist/esm/OAuth/utils/createAuthKey.js +3 -0
  42. package/dist/esm/OAuth/utils/createAuthKey.js.map +1 -1
  43. package/dist/esm/OAuth/utils/createOAuthHelper.js +262 -0
  44. package/dist/esm/OAuth/utils/createOAuthHelper.js.map +1 -0
  45. package/dist/esm/OAuth/utils/formatScope.js.map +1 -1
  46. package/dist/esm/OAuthCollection/OAuthCollection.js +190 -0
  47. package/dist/esm/OAuthCollection/OAuthCollection.js.map +1 -0
  48. package/dist/esm/OAuthCollection/index.js +3 -0
  49. package/dist/esm/OAuthCollection/index.js.map +1 -0
  50. package/dist/esm/Token/TokenCollection.js +115 -12
  51. package/dist/esm/Token/TokenCollection.js.map +1 -1
  52. package/dist/esm/Token/utils/createAuthKey.js +3 -0
  53. package/dist/esm/Token/utils/createAuthKey.js.map +1 -1
  54. package/dist/esm/constants.js +1 -0
  55. package/dist/esm/constants.js.map +1 -1
  56. package/dist/esm/index.js +2 -1
  57. package/dist/esm/index.js.map +1 -1
  58. package/dist/types/Basic/BasicCollection.d.ts +6 -4
  59. package/dist/types/Basic/BasicCollection.d.ts.map +1 -1
  60. package/dist/types/Basic/types.d.ts +20 -11
  61. package/dist/types/Basic/types.d.ts.map +1 -1
  62. package/dist/types/Basic/utils/createAuthKey.d.ts +1 -0
  63. package/dist/types/Basic/utils/createAuthKey.d.ts.map +1 -1
  64. package/dist/types/OAuth/OAuth.d.ts +8 -5
  65. package/dist/types/OAuth/OAuth.d.ts.map +1 -1
  66. package/dist/types/OAuth/index.d.ts +0 -1
  67. package/dist/types/OAuth/index.d.ts.map +1 -1
  68. package/dist/types/OAuth/types.d.ts +95 -19
  69. package/dist/types/OAuth/types.d.ts.map +1 -1
  70. package/dist/types/OAuth/utils/createAuthKey.d.ts +1 -0
  71. package/dist/types/OAuth/utils/createAuthKey.d.ts.map +1 -1
  72. package/dist/types/OAuth/utils/createOAuthHelper.d.ts +33 -0
  73. package/dist/types/OAuth/utils/createOAuthHelper.d.ts.map +1 -0
  74. package/dist/types/OAuthCollection/OAuthCollection.d.ts +27 -0
  75. package/dist/types/OAuthCollection/OAuthCollection.d.ts.map +1 -0
  76. package/dist/types/OAuthCollection/index.d.ts +3 -0
  77. package/dist/types/OAuthCollection/index.d.ts.map +1 -0
  78. package/dist/types/Token/TokenCollection.d.ts +5 -2
  79. package/dist/types/Token/TokenCollection.d.ts.map +1 -1
  80. package/dist/types/Token/types.d.ts +19 -5
  81. package/dist/types/Token/types.d.ts.map +1 -1
  82. package/dist/types/Token/utils/createAuthKey.d.ts +1 -0
  83. package/dist/types/Token/utils/createAuthKey.d.ts.map +1 -1
  84. package/dist/types/constants.d.ts +1 -0
  85. package/dist/types/constants.d.ts.map +1 -1
  86. package/dist/types/index.d.ts +2 -1
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/package.json +32 -26
  89. package/src/Basic/BasicCollection.ts +170 -18
  90. package/src/Basic/types.ts +17 -14
  91. package/src/Basic/utils/createAuthKey.ts +4 -0
  92. package/src/OAuth/OAuth.ts +111 -195
  93. package/src/OAuth/index.ts +0 -1
  94. package/src/OAuth/types.ts +171 -15
  95. package/src/OAuth/utils/createAuthKey.ts +8 -0
  96. package/src/OAuth/utils/createOAuthHelper.ts +374 -0
  97. package/src/OAuthCollection/OAuthCollection.ts +348 -0
  98. package/src/OAuthCollection/index.ts +3 -0
  99. package/src/Token/TokenCollection.ts +174 -16
  100. package/src/Token/types.ts +15 -0
  101. package/src/Token/utils/createAuthKey.ts +4 -0
  102. package/src/constants.ts +1 -0
  103. package/src/index.ts +2 -1
  104. package/dist/cjs/OAuth/OAuthCollection.js.map +0 -1
  105. package/dist/esm/OAuth/OAuthCollection.js +0 -120
  106. package/dist/esm/OAuth/OAuthCollection.js.map +0 -1
  107. package/dist/types/OAuth/OAuthCollection.d.ts +0 -21
  108. package/dist/types/OAuth/OAuthCollection.d.ts.map +0 -1
  109. package/src/OAuth/OAuthCollection.ts +0 -206
@@ -0,0 +1,348 @@
1
+ import { Token, List, makeList } from '@or-sdk/base';
2
+ import { KeyValueStorage } from '@or-sdk/key-value-storage';
3
+ import { Providers } from '@or-sdk/providers';
4
+ import { OAuth } from '../OAuth/OAuth';
5
+
6
+ import {
7
+ CreateOAuthInCollectionConfig,
8
+ CreateOAuthResult,
9
+ OAuthCollectionConfig,
10
+ OAuthApp,
11
+ OAuthCollectionInitConfig,
12
+ OAuthDynamicCollection,
13
+ OAuthService,
14
+ } from '../OAuth/types';
15
+
16
+ export class OAuthCollection {
17
+ private readonly token: Token;
18
+ private readonly providers: Providers;
19
+ private readonly discoveryUrl: string;
20
+ private readonly accountId: string | undefined;
21
+ private readonly sdkUrl: string | undefined;
22
+ private readonly eventManagerUrl: string | undefined;
23
+ private readonly providersAccountId: string | undefined;
24
+ private readonly crossAccount: boolean;
25
+ private keyValueCollection: string;
26
+ private keyValueStorage: KeyValueStorage;
27
+ private serviceName: string;
28
+
29
+ constructor(params: OAuthCollectionConfig) {
30
+ const {
31
+ token,
32
+ discoveryUrl,
33
+ accountId,
34
+ serviceName,
35
+ keyValueCollection,
36
+ eventManagerUrl,
37
+ providersAccountId,
38
+ sdkUrl,
39
+ crossAccount = true,
40
+ } = params;
41
+
42
+ this.token = token;
43
+ this.sdkUrl = sdkUrl;
44
+ this.accountId = accountId;
45
+ this.crossAccount = crossAccount;
46
+ this.discoveryUrl = discoveryUrl;
47
+ this.serviceName = serviceName || '';
48
+ this.eventManagerUrl = eventManagerUrl;
49
+ this.providersAccountId = providersAccountId;
50
+ this.keyValueCollection = keyValueCollection || serviceName || '';
51
+
52
+ this.keyValueStorage = new KeyValueStorage({
53
+ token,
54
+ discoveryUrl,
55
+ accountId: crossAccount ? accountId : undefined,
56
+ sdkUrl,
57
+ });
58
+
59
+ this.providers = new Providers({
60
+ token,
61
+ discoveryUrl,
62
+ eventManagerUrl,
63
+ providersAccountId,
64
+ });
65
+ }
66
+
67
+
68
+ /**
69
+ * Allows to explicitly (re)initialize collection parameters
70
+ */
71
+ public init(params: OAuthCollectionInitConfig): void {
72
+ const { serviceName, keyValueCollection } = params;
73
+
74
+ this.serviceName = serviceName || this.serviceName;
75
+ this.keyValueCollection = keyValueCollection || this.keyValueCollection || this.serviceName;
76
+
77
+ if (!this.serviceName) {
78
+ throw new Error('No service name provided.');
79
+ }
80
+ }
81
+
82
+
83
+ /**
84
+ * Returns array of auth keys from this collection
85
+ */
86
+ public async listAuthorizations(dynamicCollection?: string): Promise<List<string>> {
87
+ const { items: records } = await this.keyValueStorage.listKeys(
88
+ this.keyValueCollection
89
+ );
90
+
91
+ const pattern = dynamicCollection ? `::oauth-collection::${dynamicCollection}` : '::oauth::';
92
+
93
+ return makeList<string>(records.map((record) => record.key)
94
+ .filter(key => key.includes(pattern)));
95
+ }
96
+
97
+ /**
98
+ * Returns array of OAuth applications for this service
99
+ */
100
+ public async listOAuthApps(): Promise<List<OAuthApp>> {
101
+ const appsStorageRecord = await this.keyValueStorage.getValueByKey(
102
+ this.keyValueCollection,
103
+ '__authorizer_apps'
104
+ );
105
+
106
+ if (!appsStorageRecord.value) {
107
+ return makeList<OAuthApp>([]);
108
+ }
109
+
110
+ const appsRecords = appsStorageRecord.value as Array<{
111
+ label: string;
112
+ value: Omit<OAuthApp, 'name'>;
113
+ }>;
114
+
115
+ return makeList<OAuthApp>(appsRecords.map((record) => ({
116
+ name: record.label,
117
+ ...record.value,
118
+ })));
119
+ }
120
+
121
+
122
+ /**
123
+ * Returns OAuth instance for given key
124
+ */
125
+ public async getAuthorization(key: string, dynamicCollection?: string): Promise<OAuth> {
126
+ if (!this.serviceName) throw new Error('No service name provided.');
127
+ let authName = undefined;
128
+
129
+ if (dynamicCollection) {
130
+ const { value } = await this.keyValueStorage.getValueByKey(
131
+ '__authorizer_dynamic_collections',
132
+ dynamicCollection
133
+ );
134
+
135
+ if (!value) {
136
+ throw new Error('Cynamic collection name is invalid');
137
+ }
138
+
139
+ const collection = value as OAuthDynamicCollection;
140
+ if (collection.service !== this.serviceName) {
141
+ throw new Error('Dynamic Collection and is related to other service than SDK Service Name');
142
+ }
143
+
144
+ authName = key;
145
+ key = collection.authorizations[key];
146
+
147
+ } else {
148
+ const { value } = await this.keyValueStorage.getValueByKey(
149
+ this.keyValueCollection,
150
+ encodeURIComponent(key)
151
+ );
152
+
153
+ if (!value) {
154
+ throw new Error('This authorization does not exist');
155
+ }
156
+ }
157
+
158
+ if (!key.includes('::oauth')) throw new Error('The OAuth authorization key should contain "oauth" type specifier.');
159
+
160
+ return new OAuth({
161
+ authName,
162
+ authKey: key,
163
+ dynamicCollection,
164
+ discoveryUrl: this.discoveryUrl,
165
+ eventManagerUrl: this.eventManagerUrl,
166
+ keyValueCollection: this.keyValueCollection,
167
+ providersAccountId: this.providersAccountId,
168
+ sdkUrl: this.sdkUrl,
169
+ serviceName: this.serviceName,
170
+ token: this.token,
171
+ });
172
+ }
173
+
174
+
175
+ /**
176
+ * Creates a new auth record in current collection with the given config.
177
+ * @returns Object with OAuth instance connected to created auth and authorizerUrl
178
+ * to redirect the user to for completing authorization
179
+ *
180
+ * ```typescript
181
+ * const {
182
+ * authorizeUrl, // redirect user to this url for completing authorization
183
+ * instance // new instance
184
+ * } = await oAuthCollectionInstance.createAuthorization({
185
+ * authName: 'my-auth-name',
186
+ * appId: 'my-app-id',
187
+ *
188
+ * // Optional params
189
+ * sdkUrl: 'sdkapi.staging.api.onereach.ai' // SDK API url. If passed, won't be fetched from discovery.
190
+ * eventManagerUrl: 'em.staging.api.onereach.ai' // Event Manager url. If passed, won't be fetched from discovery.
191
+ * providersAccountId: 'providers-account-id-v4' // Account ID of provider account. If passed, won't be fetched from discovery.
192
+ * keyValueCollection: 'custom_collection_name' // Pass this if you using custom name for key-value collection
193
+ * // that differs from serviceName.
194
+ * destinationAccount: 'CUSTOM' or 'PROVIDER' // Allows to save authorization data to custom account.
195
+ * customAccountId: 'custom-account-uuid-v4' // Account ID for destinationAccount == "CUSTOM".
196
+ * useNextProvider: boolean (default: false) // Use authorizer-next redirect endpoint.
197
+ * userScope: 'user:read' // Scopes for Slack service.
198
+ * useNonce: true // Allows to use Nonce to avoid repetition attacks.
199
+ * });
200
+ *
201
+ * // if you want to use returned instance, you must call a method
202
+ * that returns a promise that will be resolved when the user completes authorization process
203
+ * // if not, you can omit this step
204
+ * try {
205
+ * await instance.waitForCompletion()
206
+ * } catch (e) {
207
+ * // will be called if the user does not complete authorization within 5 minutes
208
+ * }
209
+ * ```
210
+ */
211
+ public async createAuthorization(
212
+ params: CreateOAuthInCollectionConfig,
213
+ ): Promise<CreateOAuthResult> {
214
+ if (!this.serviceName) throw new Error('No service name provided.');
215
+ return await OAuth.create({
216
+ ...params,
217
+ accountId: this.accountId,
218
+ crossAccount: this.crossAccount,
219
+ discoveryUrl: this.discoveryUrl,
220
+ eventManagerUrl: this.eventManagerUrl,
221
+ keyValueCollection: this.keyValueCollection,
222
+ providersAccountId: this.providersAccountId,
223
+ sdkUrl: this.sdkUrl,
224
+ serviceName: this.serviceName,
225
+ token: this.token,
226
+ });
227
+ }
228
+
229
+
230
+ /**
231
+ * Returns a list of predefined OAuth Services
232
+ */
233
+ public async listPredefinedServices(): Promise<Record<string, unknown>[]> {
234
+
235
+ const globalServices = await this.providers.makeRequest({
236
+ method: 'GET',
237
+ route: 'authorizer/services/list',
238
+ params: {
239
+ type: 'list',
240
+ },
241
+ }) as Record<string, unknown>;
242
+
243
+
244
+ const globalServicesList = Object.keys(globalServices).map(record => {
245
+ const label = record.split('__authorization_service_')[1]
246
+ .replace(/_/g, ' ');
247
+
248
+ const value = globalServices[record];
249
+
250
+ return {
251
+ label,
252
+ value,
253
+ };
254
+ }) as Record<string, unknown>[];
255
+
256
+
257
+ const localServices = await this.keyValueStorage.listKeys(
258
+ '__authorization_service_predefined_services_local',
259
+ undefined,
260
+ true
261
+ ) as unknown as Record<string, Record<string, string>[]>;
262
+
263
+
264
+ const localServicesList = localServices.items.map(el => {
265
+ const label = el.key
266
+ .split('__authorization_service_')[1]
267
+ .replace(/_/g, ' ') + ' (local)';
268
+
269
+ const value = el.value;
270
+ return {
271
+ label,
272
+ value,
273
+ };
274
+ });
275
+
276
+ return [...globalServicesList, ...localServicesList];
277
+ }
278
+
279
+
280
+ /**
281
+ * Defines a Local service
282
+ */
283
+ public async defineService(params: Omit<OAuthService, 'serviceName'>): Promise<void> {
284
+ if (!this.serviceName) throw new Error('No service name provided.');
285
+ const newService = {
286
+ ...params,
287
+ serviceName: this.serviceName,
288
+ } as OAuthService;
289
+
290
+ this.keyValueStorage.setValueByKey(
291
+ '__authorization_service_predefined_services_local',
292
+ this.serviceName,
293
+ newService
294
+ );
295
+ }
296
+
297
+
298
+ /**
299
+ * Creates a Dynamic OAuth collection
300
+ */
301
+ public async createDynamicCollection(dynamicCollectionName: string): Promise<void> {
302
+ if (!this.serviceName) throw new Error('No service name provided.');
303
+ if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
304
+ const { value } = await this.keyValueStorage.getValueByKey(
305
+ '__authorizer_dynamic_collections',
306
+ dynamicCollectionName
307
+ );
308
+ const collection = value as OAuthDynamicCollection;
309
+
310
+ if (!value) {
311
+ await this.keyValueStorage.setValueByKey('__authorizer_dynamic_collections', dynamicCollectionName, {
312
+ name: dynamicCollectionName,
313
+ type: 'oauth',
314
+ service: this.keyValueCollection,
315
+ serviceConfigName: this.serviceName,
316
+ authorizations: {},
317
+ });
318
+ } else if (collection.type === 'oauth' && collection.service === this.serviceName) {
319
+ throw new Error('Same collection already exists');
320
+ } else {
321
+ throw new Error('Different collection exists with this name');
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Deletes a Dynamic OAuth collection
327
+ */
328
+ public async deleteDynamicCollection(dynamicCollectionName: string): Promise<void> {
329
+ if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
330
+ const { value } = await this.keyValueStorage.getValueByKey(
331
+ '__authorizer_dynamic_collections',
332
+ dynamicCollectionName
333
+ );
334
+ const collection = value as OAuthDynamicCollection;
335
+
336
+ await Promise.all(
337
+ Object.keys(collection.authorizations)
338
+ .map(authName => {
339
+ return this.keyValueStorage.deleteKey(
340
+ collection.service,
341
+ encodeURIComponent(collection.authorizations[authName])
342
+ );
343
+ })
344
+ ).catch(() => {});
345
+
346
+ await this.keyValueStorage.deleteKey('__authorizer_dynamic_collections', dynamicCollectionName);
347
+ }
348
+ }
@@ -0,0 +1,3 @@
1
+ export { OAuthCollection } from './OAuthCollection';
2
+
3
+ export * from '../OAuth/types';
@@ -1,17 +1,21 @@
1
1
  import { makeList, List } from '@or-sdk/base';
2
2
  import { KeyValueStorage } from '@or-sdk/key-value-storage';
3
+ import { Providers } from '@or-sdk/providers';
3
4
  import { v4 as uuidv4 } from 'uuid';
4
- import { createAuthKey } from './utils/createAuthKey';
5
5
 
6
6
  import {
7
7
  TokenCollectionConfig,
8
8
  CreateTokenAuthInCollectionConfig,
9
9
  TokenAuthData,
10
+ TokenDynamicCollection,
10
11
  } from './types';
12
+ import { createAuthKey, createDynamicKey } from './utils/createAuthKey';
13
+
11
14
 
12
15
  export class TokenCollection {
13
16
  private serviceName: string;
14
17
  private readonly keyValueStorage: KeyValueStorage;
18
+ private readonly providers: Providers;
15
19
 
16
20
  constructor(params: TokenCollectionConfig) {
17
21
  const { token, discoveryUrl, serviceName, accountId } = params;
@@ -22,6 +26,11 @@ export class TokenCollection {
22
26
  discoveryUrl,
23
27
  accountId,
24
28
  });
29
+
30
+ this.providers = new Providers({
31
+ token,
32
+ discoveryUrl,
33
+ });
25
34
  }
26
35
 
27
36
 
@@ -38,17 +47,30 @@ export class TokenCollection {
38
47
  /**
39
48
  * Returns array of auth keys from this collection
40
49
  */
41
- public async listAuthorizations(): Promise<List<string>> {
42
- const { items: records } = await this.keyValueStorage.listKeys(this.serviceName);
50
+ public async listAuthorizations(dynamicCollectionName?: string): Promise<List<string>> {
51
+ const { items: records } = await this.keyValueStorage.listKeys(this.serviceName, '', false);
43
52
 
44
- return makeList<string>(records.map((record) => record.key).filter(key => key.includes('::token')));
53
+ const pattern = dynamicCollectionName ? `::token-collection::${dynamicCollectionName}` : '::token::';
54
+
55
+ return makeList<string>(records.map((record) => record.key).filter(key => key.includes(pattern)));
45
56
  }
46
57
 
47
58
  /**
48
59
  * Returns TokenAuth instance for given key
49
60
  */
50
- public async getAuthorization(key: string): Promise<TokenAuthData> {
61
+ public async getAuthorization(key: string, dynamicCollectionName: string): Promise<TokenAuthData> {
51
62
  if (!this.serviceName) throw new Error('Service name is not defined.');
63
+
64
+ if (dynamicCollectionName) {
65
+ const { value } = await this.keyValueStorage.getValueByKey(
66
+ '__authorizer_dynamic_collections',
67
+ dynamicCollectionName
68
+ );
69
+ const collection = value as TokenDynamicCollection;
70
+ if (!collection) throw new Error('Dynamic collection name is invalid');
71
+
72
+ key = collection.authorizations[key];
73
+ }
52
74
  if (!key.includes('::token')) throw new Error('The Token authorization key should contain "token" type specifier.');
53
75
 
54
76
 
@@ -59,7 +81,7 @@ export class TokenCollection {
59
81
 
60
82
  const authData = record.value as Omit<TokenAuthData, 'key'>;
61
83
 
62
- if (!authData.auth_name || !authData.date_created) {
84
+ if (!(authData.auth_name || authData._auth_name) || !(authData.date_created || authData._date_created)) {
63
85
  throw new Error('Authorization is invalid.');
64
86
  }
65
87
 
@@ -72,35 +94,83 @@ export class TokenCollection {
72
94
 
73
95
  /**
74
96
  * Creates a new auth record in current collection with the given config.
75
- * @returns TokenCollection instance connected to created auth
97
+ * @returns TokenAuthData object
76
98
  *
77
99
  * ```typescript
78
- * const tokenCollectionData = await tokenCollectionInstance.createAuthorization({
100
+ * const tokenAuthData = await tokenCollectionInstance.createAuthorization({
79
101
  * authName: 'my-auth-name',
80
102
  * credentials: {
81
103
  * token: 'secrettoken'
82
- * }
104
+ * },
105
+ * dynamicCollection: 'my-dynamic-collection' // Optional
83
106
  * });
84
107
  * ```
85
108
  */
86
109
  public async createAuthorization(
87
110
  params: CreateTokenAuthInCollectionConfig
88
111
  ): Promise<TokenAuthData> {
89
- const { authName, credentials } = params;
112
+ const { authName, credentials, dynamicCollection, destinationAccount = 'CURRENT', customAccountId } = params;
90
113
 
91
114
  if (!this.serviceName) throw new Error('Service name is not defined.');
92
115
  if (!authName || !credentials) throw new Error('Invalid authorization parameters passed.');
93
116
 
94
117
  const id = uuidv4();
95
- const authKey = createAuthKey(id, authName);
118
+ const authKey = dynamicCollection ? createDynamicKey(id, dynamicCollection) : createAuthKey(id, authName);
96
119
 
97
120
  const authData = {
98
121
  ...credentials,
99
122
  auth_name: authName,
100
- date_created: new Date().toISOString(),
123
+ _date_created: new Date().toISOString(),
101
124
  } as Omit<TokenAuthData, 'key'>;
102
125
 
103
- await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), authData);
126
+ if (dynamicCollection) {
127
+ const { value } = await this.keyValueStorage.getValueByKey('__authorizer_dynamic_collections', dynamicCollection);
128
+
129
+ const collection = (value || {
130
+ name: dynamicCollection,
131
+ type: 'token',
132
+ service: this.serviceName,
133
+ serviceConfigName: this.serviceName,
134
+ authorizations: {},
135
+ }) as TokenDynamicCollection;
136
+
137
+ if (collection.type !== 'token' || collection.service !== this.serviceName) {
138
+ throw new Error('Dynamic collection\'s type or service is invalid');
139
+ }
140
+
141
+ collection.authorizations[authName] = authKey;
142
+ await this.keyValueStorage.setValueByKey('__authorizer_dynamic_collections', dynamicCollection, collection);
143
+ }
144
+
145
+ // Accounts handling
146
+ if (destinationAccount === 'CURRENT') {
147
+ await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), authData);
148
+ } else {
149
+ const localRecord = {
150
+ auth_name: authData.auth_name,
151
+ isRemote: true,
152
+ id,
153
+ };
154
+
155
+ if (destinationAccount === 'CUSTOM' && !customAccountId) {
156
+ throw new Error('Custom Account ID is required if destinationAccount === "CUSTOM"');
157
+ }
158
+
159
+ await this.providers.makeRequest({
160
+ route: 'authorizer/redirect',
161
+ params: {
162
+ method: 'PUT',
163
+ data: {
164
+ authData,
165
+ id,
166
+ storeAccount: destinationAccount,
167
+ storeCustomAccountId: destinationAccount === 'CUSTOM' ? customAccountId : undefined,
168
+ },
169
+ },
170
+ }).catch(() => { throw new Error('Could not save token to the specified account');});
171
+
172
+ await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(authKey), localRecord);
173
+ }
104
174
 
105
175
  return {
106
176
  ...authData,
@@ -118,18 +188,25 @@ export class TokenCollection {
118
188
  ): Promise<TokenAuthData> {
119
189
  if (!this.serviceName) throw new Error('Service name is not defined.');
120
190
  if (!newCredentials) throw new Error('New credentials are empty or invalid');
121
- if (!tokenAuth || !tokenAuth.auth_name || !tokenAuth.date_created)
191
+ if (!tokenAuth || !tokenAuth.auth_name || !(tokenAuth.date_created || tokenAuth._date_created)) {
122
192
  throw new Error('Token authorization data is invalid');
193
+ }
123
194
 
124
195
  const updatedData = {
125
196
  ...tokenAuth,
126
197
  ...newCredentials,
198
+ auth_name: tokenAuth.auth_name,
199
+ _date_created: tokenAuth._date_created,
127
200
  key: undefined,
128
201
  };
129
202
 
130
- const response = await this.keyValueStorage.setValueByKey(this.serviceName, encodeURIComponent(tokenAuth.key), updatedData);
203
+ const response = await this.keyValueStorage.setValueByKey(
204
+ this.serviceName,
205
+ encodeURIComponent(tokenAuth.key),
206
+ updatedData
207
+ );
131
208
 
132
- const updatedRecord = response.value as Omit<TokenAuthData, 'key'>;
209
+ const updatedRecord = response.value;
133
210
  return {
134
211
  ...updatedRecord,
135
212
  key: tokenAuth.key,
@@ -143,6 +220,87 @@ export class TokenCollection {
143
220
  public async deleteAuthorization(key: string): Promise<void> {
144
221
  if (!this.serviceName) throw new Error('Service name is not defined.');
145
222
  if (!key) throw new Error('Key is missing or invalid');
223
+
224
+ if (key.includes('::token-collection::')) {
225
+ const dynamicCollectionName = key.split('::')[2].split(' ')[0];
226
+ const { value } = await this.keyValueStorage.getValueByKey(
227
+ '__authorizer_dynamic_collections',
228
+ dynamicCollectionName
229
+ );
230
+
231
+ const collection = value as TokenDynamicCollection;
232
+ if (collection) {
233
+ const authName = Object.keys(collection.authorizations)
234
+ .find(name => collection.authorizations[name] === key);
235
+
236
+ if (authName) {
237
+ delete collection.authorizations[authName];
238
+ await this.keyValueStorage.setValueByKey(
239
+ '__authorizer_dynamic_collections',
240
+ dynamicCollectionName,
241
+ collection
242
+ );
243
+ }
244
+ }
245
+ }
146
246
  await this.keyValueStorage.deleteKey(this.serviceName, encodeURIComponent(key));
147
247
  }
248
+
249
+
250
+ /**
251
+ * Creates a Dynamic Token collection
252
+ */
253
+ public async createDynamicCollection(dynamicCollectionName: string): Promise<void> {
254
+ if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
255
+ const { value } = await this.keyValueStorage.getValueByKey(
256
+ '__authorizer_dynamic_collections',
257
+ dynamicCollectionName
258
+ );
259
+ const collection = value as TokenDynamicCollection;
260
+
261
+ if (!value) {
262
+ await this.keyValueStorage.setValueByKey(
263
+ '__authorizer_dynamic_collections',
264
+ dynamicCollectionName,
265
+ {
266
+ name: dynamicCollectionName,
267
+ type: 'token',
268
+ service: this.serviceName,
269
+ serviceConfigName: this.serviceName,
270
+ authorizations: {},
271
+ });
272
+ } else if (collection.type === 'oauth' && collection.service === this.serviceName) {
273
+ throw new Error('Same collection already exists');
274
+ } else {
275
+ throw new Error('Different collection exists with this name');
276
+ }
277
+ }
278
+
279
+
280
+ /**
281
+ * Deletes a Dynamic collection
282
+ */
283
+ public async deleteDynamicCollection(dynamicCollectionName: string): Promise<void> {
284
+ if (!dynamicCollectionName) throw new Error('Dynamic collection name is empty or invalid');
285
+ const { value } = await this.keyValueStorage.getValueByKey(
286
+ '__authorizer_dynamic_collections',
287
+ dynamicCollectionName
288
+ );
289
+ const collection = value as TokenDynamicCollection;
290
+
291
+ await Promise.all(
292
+ Object.keys(collection.authorizations)
293
+ .map(authName => {
294
+ return this.keyValueStorage.deleteKey(
295
+ collection.service,
296
+ encodeURIComponent(collection.authorizations[authName])
297
+ );
298
+ })
299
+ ).catch(() => {});
300
+
301
+ await this.keyValueStorage.deleteKey(
302
+ '__authorizer_dynamic_collections',
303
+ dynamicCollectionName
304
+ );
305
+ }
148
306
  }
@@ -38,6 +38,9 @@ export type CreateTokenAuthConfig = {
38
38
  */
39
39
  token: Token;
40
40
  discoveryUrl: string;
41
+ dynamicCollection?: string;
42
+ destinationAccount: 'CURRENT' | 'PROVIDER' | 'CUSTOM';
43
+ customAccountId?: string;
41
44
  };
42
45
 
43
46
  export type CreateTokenAuthInCollectionConfig = Omit<CreateTokenAuthConfig, 'serviceName' | 'discoveryUrl' | 'token'>;
@@ -51,3 +54,15 @@ export type TokenCollectionConfig = {
51
54
  serviceName: string;
52
55
  accountId?: string;
53
56
  };
57
+
58
+ export type TokenDynamicCollection = {
59
+ name: string;
60
+ type: string;
61
+ service: string;
62
+ serviceConfigName: string;
63
+ authorizations: {
64
+ [key: string]: string;
65
+ };
66
+ appId?: string;
67
+ scope?: string;
68
+ };
@@ -1,3 +1,7 @@
1
1
  export const createAuthKey = (id: string, authName: string): string => {
2
2
  return `${id}::token::${authName}`;
3
3
  };
4
+
5
+ export function createDynamicKey(id: string, dynamicCollection: string): string {
6
+ return `${id}::token-collection::${dynamicCollection} collection auth`;
7
+ }
package/src/constants.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export const SERVICE_PROVIDER_PATH = '/authorizer/services/list';
2
2
  export const OAUTH_REDIRECT_PROVIDER_PATH = '/authorizer/redirect';
3
+ export const NEXT_OAUTH_REDIRECT_PROVIDER_PATH = '/authorizer-next/redirect';
3
4
 
4
5
  export enum AuthStatus {
5
6
  NEW = 'NEW',
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { BasicCollection } from './Basic/index';
2
2
  export { TokenCollection } from './Token/index';
3
- export { OAuth, OAuthCollection } from './OAuth/index';
3
+ export { OAuth } from './OAuth/index';
4
+ export { OAuthCollection } from './OAuthCollection/index';
4
5
 
5
6
  export * from './types';