genesys-cloud-client-auth 0.0.1 → 0.0.2-PCM-1937.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/LICENSE +2 -2
  3. package/README.md +461 -2
  4. package/dist/asset-manifest.json +161 -161
  5. package/dist/deploy-info.json +22 -0
  6. package/dist/genesys-cloud-client-auth.browser.min.js +1 -1
  7. package/dist/genesys-cloud-client-auth.browser.min.js.map +1 -1
  8. package/dist/index.html +1 -1
  9. package/dist/lib/cjs/authenticator.d.ts +60 -13
  10. package/dist/lib/cjs/authenticator.js +80 -44
  11. package/dist/lib/cjs/authenticator.js.map +1 -1
  12. package/dist/lib/cjs/index.d.ts +11 -2
  13. package/dist/lib/cjs/index.js +11 -1
  14. package/dist/lib/cjs/index.js.map +1 -1
  15. package/dist/lib/cjs/parse-redirect.d.ts +5 -0
  16. package/dist/lib/cjs/parse-redirect.js +5 -0
  17. package/dist/lib/cjs/parse-redirect.js.map +1 -1
  18. package/dist/lib/cjs/types.d.ts +24 -0
  19. package/dist/lib/cjs/utils.d.ts +45 -4
  20. package/dist/lib/cjs/utils.js +47 -3
  21. package/dist/lib/cjs/utils.js.map +1 -1
  22. package/dist/lib/cjs/version.js +1 -1
  23. package/dist/lib/es/authenticator.d.ts +60 -13
  24. package/dist/lib/es/authenticator.js +80 -44
  25. package/dist/lib/es/authenticator.js.map +1 -1
  26. package/dist/lib/es/index.d.ts +11 -2
  27. package/dist/lib/es/index.js +11 -2
  28. package/dist/lib/es/index.js.map +1 -1
  29. package/dist/lib/es/parse-redirect.d.ts +5 -0
  30. package/dist/lib/es/parse-redirect.js +5 -0
  31. package/dist/lib/es/parse-redirect.js.map +1 -1
  32. package/dist/lib/es/types.d.ts +24 -0
  33. package/dist/lib/es/utils.d.ts +45 -4
  34. package/dist/lib/es/utils.js +45 -2
  35. package/dist/lib/es/utils.js.map +1 -1
  36. package/dist/lib/es/version.js +1 -1
  37. package/dist/static/js/{main.6a720c22.chunk.js → main.08336ad2.chunk.js} +2 -2
  38. package/dist/static/js/{main.6a720c22.chunk.js.map → main.08336ad2.chunk.js.map} +1 -1
  39. package/dist/static/js/{runtime-main.429a13c7.js → runtime-main.326c80c2.js} +2 -2
  40. package/dist/static/js/{runtime-main.429a13c7.js.map → runtime-main.326c80c2.js.map} +1 -1
  41. package/package.json +73 -67
package/CHANGELOG.md CHANGED
@@ -5,4 +5,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5
5
 
6
6
  # [Unreleased](https://github.com/MyPureCloud/genesys-cloud-client-auth/compare/v0.0.1...HEAD)
7
7
 
8
+ ### Added
9
+ * [PCM-1937](https://inindca.atlassian.net/browse/PCM-1937) – migrated to new build pipeline
10
+
8
11
  # [v0.0.1](https://github.com/MyPureCloud/genesys-cloud-client-auth/tags/v0.0.1)
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Genesys Cloud Services, Inc.
3
+ Copyright (c) 2022 Genesys Cloud Services, Inc.
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
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,5 +1,464 @@
1
+ [![Build Status](https://travis-ci.com/MyPureCloud/genesys-cloud-client-auth.svg?branch=main)](https://travis-ci.com/MyPureCloud/genesys-cloud-client-auth)
2
+ [![npm version](https://badge.fury.io/js/genesys-cloud-client-auth.svg)](https://badge.fury.io/js/genesys-cloud-client-auth)
3
+ [![codecov](https://codecov.io/gh/MyPureCloud/genesys-cloud-client-auth/branch/master/graph/badge.svg)](https://codecov.io/gh/MyPureCloud/genesys-cloud-client-auth)
4
+ [![dependabot-status](https://flat.badgen.net/dependabot/MyPureCloud/genesys-cloud-client-auth/?icon=dependabot)](https://dependabot.com)
5
+
1
6
  # genesys-cloud-client-auth
2
7
  Small, lightweight library and app to handle authentication for client applications. Big advantage is utilization of popup windows to authenticate apps within iframes.
8
+ This library only supports implicit logins for use within a front-end web application.
9
+
10
+ * [Install](#install)
11
+ * [Usage](#usage)
12
+ * [Standard Usage](#usage)
13
+ * [Popup Authentication (for Iframes)](#popup-auth)
14
+ * [API](#api)
15
+ * [Limitations](#limitations)
16
+
17
+
18
+ ## Install
19
+ ``` sh
20
+ npm add genesys-cloud-client-auth
21
+ # or
22
+ yarn add genesys-cloud-client-auth
23
+ ```
24
+
25
+ Or you can download directly from the browser:
26
+
27
+ ``` html
28
+ <!-- change out the domain if desired -->
29
+ <script src="https://apps.mypurecloud.com/client-auth/genesys-cloud-client-auth.browser.min.js"></script>
30
+ ```
31
+
32
+ ## Usage
33
+ ``` typescript
34
+ import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
35
+
36
+ const clientId = 'Your Oauth ClientID';
37
+ const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
38
+ /* these are the defaults */
39
+ environment: 'mypurecloud.com',
40
+ persist: false,
41
+ storageKey: 'gc_client_auth_data',
42
+ debugMode: false
43
+ });
44
+
45
+ authenticator.loginImplicitGrant({
46
+ redirectUri: 'https://myapp.example.com/app/', // whatever valid redirect URI is configured for your Oauth client
47
+ state: '', // optional state to return after authentication
48
+ /* All optional – see the advanced usage and/or API section for these – defaults listed below */
49
+ org: '',
50
+ provider: '',
51
+ usePopupAuth: false,
52
+ popupTimeout: 15000
53
+ }).then((data: IAuthData) => {
54
+ /* data will contain authentication information like accessToken */
55
+ }).catch(error => {
56
+ /* authentication failed */
57
+ });
58
+ ```
59
+
60
+ ## Popup Auth
61
+ For applications that are iframed into a parent application, some identity providers will prevent authentication within an iframe using the `X-Frame-Options`. To work around this issue the iframed application can open a popup window and localStorage to perform the authentication.
62
+
63
+ #### Auth Flow Using Popup
64
+
65
+ ```
66
+ Iframed App Redirect App Login
67
+ | | |
68
+ |------- (1) -------------------------->|
69
+ | | |
70
+ | |<------ (2) ------|
71
+ | | |
72
+ |<------ (3) --------| |
73
+ ```
74
+
75
+ 1. The Iframed app will initiate a login by opening a new popup window with the url to the login page. It will then setup a listener on localStorage events.
76
+ 1. Once authenticated, the login page will redirect to the "Redirect App" (more on this below).
77
+ 1. The Redirect App will parse the authentication data and save it to localStorage triggering a localStorage event which the Iframed App is listening on. The Redirect App should then close itself.
78
+
79
+ > IMPORTANT: If you are going to utilize the helper application located at `https://apps.{domain}/client-auth`, make sure to add it to your Oauth Client's approved redirects.
80
+
81
+ #### Popup Auth Usage
82
+ ``` typescript
83
+ import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
84
+
85
+ const clientId = 'Your Oauth ClientID';
86
+ const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
87
+ environment: 'mypurecloud.com',
88
+ persist: true, // this is required to use popup auth
89
+ storageKey: 'gc_client_auth_data',
90
+ debugMode: false // setting to `true` for popup auth will help with debugging
91
+ });
92
+
93
+ authenticator.loginImplicitGrant({
94
+ // if left falsy, the `https://apps.{env}/client-auth/` app will be used for the redirectUri
95
+ // else, your redirect will need to implement the parsing of the token (see next step)
96
+ redirectUri: 'https://myapp.example.com/app/',
97
+ usePopupAuth: true,
98
+ popupTimeout: 15000 // default amount
99
+ }).then((data: IAuthData) => {
100
+ /* data will contain authentication information like accessToken */
101
+ }).catch(error => {
102
+ /* authentication failed */
103
+ if (error.name === 'TIMEOUT_ERROR') {
104
+ // this error will trigger after the `popupTimeout` expires without valid auth data saved
105
+ // this could be an indication that the user has popups blocked
106
+ // you will need to add application logic to handle these errors
107
+ }
108
+ });
109
+ ```
110
+
111
+ If you are not using the default redirect to `/client-auth`, then your redirect application can use the following function to perform the necessary parsing and saving to localStorage:
112
+
113
+ ``` typescript
114
+ import { handleRedirectFromLogin } from 'genesys-cloud-client-auth';
115
+
116
+ try {
117
+ // this will parse and save auth data to localStorage
118
+ handleRedirectFromLogin();
119
+ } catch (error) {
120
+ // it could error for multiple reasons.
121
+ // mainly, if the auth hash is not present
122
+ // or if there is no storage ID as the state field
123
+ }
124
+ ```
125
+
126
+ It can also be used directly in the HTML:
127
+
128
+ ``` html
129
+ <script src="https://apps.mypurecloud.com/client-auth/genesys-cloud-client-auth.browser.min.js"></script>
130
+ <script>
131
+ try {
132
+ GenesysCloudClientAuth.handleRedirectFromLogin();
133
+ console.log('Successfully parsed params from hash');
134
+ } catch (error) {
135
+ console.warn(`Error parsing auth params from hash – ${error.name}: "${error.message}"`);
136
+ }
137
+ </script>
138
+ ```
139
+
140
+ The `redirectUri` is very important here. There are two options:
141
+ 1. If no `redirectUri` is provided, client-auth will redirect to `https://{domain}/client-auth`. If this method is used, make sure your Oauth client whitelists `https://{domain}/client-auth` as a valid redirectUri.
142
+ 1. If a `redirectUri` is provided, it can use the `handleRedirectFromLogin()` function listed below to perform the necessary parsing and saving to localStorage (more on that in step 2).
143
+
144
+ ## API
145
+
146
+ ### `authenticatorFactory()`
147
+ Factory function to generate a singleton instance of a ClientAuthenticator class.
148
+ If an instance has already been created for passed in `clientId`, that instance
149
+ will be returned _without_ updating the original configuration.
150
+
151
+ Declaration:
152
+ ``` ts
153
+ authenticatorFactory: (clientId: string, config: Partial<IAuthenticatorConfig>) => GenesysCloudClientAuthenticator;
154
+ ```
155
+
156
+ Params:
157
+ * `client: string` – Oauth Client ID
158
+ * `config: Partial<IAuthenticatorConfig>` – Optional; configuration for the ClientAuthenticator instance. Available options (with defaults):
159
+ ``` ts
160
+ interface IAuthenticatorConfig {
161
+ /**
162
+ * Genesys Cloud domain.
163
+ * Defaults to: `'mypurecloud.com'`
164
+ */
165
+ environment: string;
166
+
167
+ /**
168
+ * Persist authentication data to localStorage.
169
+ * Note: this is required if using popup authentication
170
+ * Defaults to: `false`
171
+ */
172
+ persist: boolean;
173
+
174
+ /**
175
+ * Storage key to save auth data to localStorage.
176
+ * Defaults to: `gc_client_auth_data`
177
+ */
178
+ storageKey: string;
179
+
180
+ /**
181
+ * Allow for extra console logs for debugging
182
+ * Defaults to: `false`
183
+ */
184
+ debugMode: boolean;
185
+ }
186
+ ```
187
+
188
+ Returns: Singleton GenesysCloudClientAuthenticator instance
189
+
190
+ ### GenesysCloudClientAuthenticator
191
+ Class to manage authentication and state. It is recommended to use the `authenticatorFactory` to construct a singleton instance of this class.
192
+
193
+ #### Properties
194
+
195
+ ##### `authenticator.clientId`
196
+ Oauth client id
197
+
198
+ ##### `authenticator.VERSION`
199
+ client-auth version
200
+
201
+ ##### `authenticator.authData`
202
+ current authencation data for this instance. default is an empty object `{}`. Definition:
203
+ ``` ts
204
+ interface IAuthData {
205
+ /** access token received from login */
206
+ accessToken?: string;
207
+ /** optional state returned from login */
208
+ state?: string;
209
+ /** time at which the token expires */
210
+ tokenExpiryTime?: number;
211
+ /** time at which the token expires in ISO string format */
212
+ tokenExpiryTimeString?: string;
213
+ /** error that may have occurred during login */
214
+ error?: string;
215
+ /** error description that may have occurred during login */
216
+ error_description?: string;
217
+ }
218
+ ```
219
+
220
+ ##### `authenticator.config`
221
+ current configuration for this instance
222
+
223
+ ##### `authenticator.environment`
224
+ current environment. Ex. `mypurecloud.com`.
225
+ > Note: do not update this property individually. Use `authenticator.setEnvironment(env: string)` if updating it is necessary.
226
+
227
+ ##### `authenticator.basePath`
228
+ base api path – utilizing the `environment` varialbe
229
+
230
+ ##### `authenticator.authUrl`
231
+ base auth path – utilizing the `environment` varialbe
232
+
233
+ #### Methods
234
+
235
+ ##### `constructor()`
236
+ Construct a new Authenticator instance. It is recommended you use the `authenticatorFactory()` to construct a singleton for each necessary Oauth client.
237
+
238
+ Declaration:
239
+ ``` ts
240
+ constructor (clientId: string, config: Partial<IAuthenticatorConfig> = {});
241
+ ```
242
+
243
+ Params:
244
+ * `client: string` – Oauth Client ID
245
+ * `config: Partial<IAuthenticatorConfig>` – Optional; configuration for the ClientAuthenticator instance. See [authenticatorFactory()](#authenticatorfactory) for more details.
246
+
247
+ Returns: `GenesysCloudClientAuthenticator` instance
248
+
249
+ ##### `authenticator.loginImplicitGrant()`
250
+ Initiates the implicit grant login flow. Will attempt to load the token from local storage, if enabled.
251
+
252
+ Declaration:
253
+ ``` ts
254
+ loginImplicitGrant(opts?: ILoginOptions, existingAuthData?: IAuthData): Promise<IAuthData | undefined>;
255
+ ```
256
+
257
+ Params:
258
+ * `opts: ILoginOptions` – Options to login with
259
+ ``` ts
260
+ interface ILoginOptions {
261
+ /**
262
+ * The redirect URI of the OAuth Implicit Grant client. Not needed if `usePopupAuth: true` _and_
263
+ * the consuming application wishes to use the standard redirect of genesys-cloud-client-auth
264
+ * standalone app.
265
+ */
266
+ redirectUri?: string;
267
+ /**
268
+ * Any state needed when returning from login
269
+ */
270
+ state?: string;
271
+ /**
272
+ * The organization name that would normally used when specifying an organization name when logging in.
273
+ * This is only used when a provider is also specified.
274
+ */
275
+ org?: string;
276
+ /**
277
+ * Authentication provider to log in with e.g. okta, adfs, salesforce, onelogin.
278
+ * This is only used when an org is also specified.
279
+ */
280
+ provider?: string;
281
+ /**
282
+ * Use a popup window to open to the login page.
283
+ */
284
+ usePopupAuth?: boolean;
285
+ /**
286
+ * Timeout for how long the auth pop should remain open before timing out
287
+ * and rejecting the loginImplicitGrant call. This is only used in conjunction
288
+ * with `usePopupAuth`.
289
+ */
290
+ popupTimeout?: number;
291
+ }
292
+ ```
293
+ * `existingAuthData?: IAuthData` – Optional; authentication data to use. default will be parsed from url hash
294
+
295
+ Returns: promise containing `IAuthData` (see [authenticator.authData](#authenticator.authData) for definition)
296
+
297
+ ##### `authenticator.setEnvironment()`
298
+ Sets the environment, baseUrl, and authUrl used by the session
299
+
300
+ Declaration:
301
+ ``` ts
302
+ setEnvironment(environment?: string): void;
303
+ ```
304
+
305
+ Params:
306
+ * `environment?: string` –  (Optional, default "mypurecloud.com") Environment the instance uses, e.g. mypurecloud.ie, mypurecloud.com.au, etc.
307
+
308
+ Returns: void
309
+
310
+ ##### `authenticator.clearAuthData()`
311
+ Will clear current auth data from localStorage.
312
+
313
+ > NOTE: this will _not_ log the user out. Using `logout()`
314
+ for logging out
315
+
316
+ Declaration:
317
+ ``` ts
318
+ clearAuthData(): void;
319
+ ```
320
+
321
+ Params: none
322
+
323
+ Returns: void
324
+
325
+ ##### `authenticator.logout()`
326
+ Clears auth data from localStorage and redirects the user to the GenesysCloud logout page
327
+
328
+ Declaration:
329
+ ``` ts
330
+ logout(logoutRedirectUri?: string): void;
331
+ ```
332
+
333
+ Params:
334
+ * `logoutRedirectUri?: string` – Optional, redirectUri to pass to the logout page
335
+
336
+ Returns: void
337
+
338
+ ##### `authenticator.setAccessToken()`
339
+ Sets the access token on the authenticator instance and localStorage (if configured)
340
+
341
+ Declaration:
342
+ ``` ts
343
+ setAccessToken(token: string): void;
344
+ ```
345
+
346
+ Params:
347
+ * `token: string` – The access token
348
+
349
+ Returns: void
350
+
351
+ ##### `authenticator.testAccessToken()`
352
+ Test an accessToken by using it to make an API call. It will resolve
353
+ if the token is valid, and will reject if it is not valid.
354
+
355
+ Declaration:
356
+ ``` ts
357
+ testAccessToken(token: string): Promise<any>;
358
+ ```
359
+
360
+ Params:
361
+ * `token: string` – accessToken to test
362
+
363
+ Returns: promise that will resolve or reject depending on the validity of the token passed in
364
+
365
+ ##### `authenticator.parseDate()`
366
+ Parses an ISO-8601 string representation of a date value.
367
+
368
+ Declaration:
369
+ ``` ts
370
+ parseDate (str: string): Date;
371
+ ```
372
+
373
+ Params:
374
+ * `str: string` – The date value as a string.
375
+
376
+ Returns: The parsed date object.
377
+
378
+ ### `handleRedirectFromLogin()`
379
+ Helper function to parse the auth data opened from a popup authentication window.
380
+ It will save the auth data to localStorage.
381
+
382
+ > Note: this will throw errors if it cannot parse or save the data correctly
383
+
384
+ Declaration:
385
+ ``` ts
386
+ handleRedirectFromLogin: () => void;
387
+ ```
388
+
389
+ Params: none
390
+
391
+ Returns: void
392
+
393
+ ### `Utils`
394
+ Utility functions to supplement and extend usage.
395
+
396
+ #### `utils.parseOauthParams()`
397
+ Utility to parse the auth data returned from the login page and return
398
+ authentication data as an object.
399
+
400
+ > Note: this will throw errors if it cannot parse or save the data correctly
401
+
402
+ Declaration:
403
+ ``` ts
404
+ parseOauthParams: (hash?: string): IAuthData;
405
+ ```
406
+
407
+ Params:
408
+ * `hash?: string` – Optional; hash to parse (default `window.location.hash`)
409
+
410
+ Returns: authentication data parsed from the passed in hash
411
+
412
+ #### `utils.tokenWasIssuedAt()`
413
+ Determine when a token was issued at by subtracting the validity
414
+ time from the expires at time.
415
+
416
+ Declaration:
417
+ ``` ts
418
+ tokenWasIssuedAt (expiresAtMs: number, expiresInMs: number): number;
419
+ ```
420
+
421
+ Params:
422
+ * `expiresAtMs: number` – epoch time (in milliseconds) for when the token will expire
423
+ * `expiresInMs: number` – milliseconds for how long the token is valid for
424
+
425
+ Returns: milliseconds since epoch time
426
+
427
+ #### `utils.isIssuedTimeWithinTimeframe()`
428
+ Determine if a token was issued within a given timeframe window. Example may be:
429
+ a token is received (either from localStorage or some other way) and you need
430
+ to be able to tell if it was issued within the last 10 minutes. Use this function
431
+ as follows:
432
+
433
+ ``` ts
434
+ const tokenExpiryTime = 1624611600000; // "2021-06-25 09:00.000Z"
435
+ const tokenExpiresIn = 86400000; // 1 day: meaning token was issuedAt "2021-06-24 09:00.000Z"
436
+ const timeframe = 600000; // 10 minutes
437
+ const startTime = 1624525260000; // "2021-06-24 09:01.000Z": 1 minute after issued time
438
+
439
+ const willBeTrue = isIssuedTimeWithinTimeframe(
440
+ tokenExpiryTime,
441
+ tokenExpiresIn,
442
+ timeframe,
443
+ startTime
444
+ );
445
+ ```
446
+
447
+ Declaration:
448
+ ``` ts
449
+ isIssuedTimeWithinTimeframe: (expiresAtMs: number, expiresInMs?: number, timeframe?: number, startTime?: number) => boolean;
450
+ ```
451
+
452
+ Params:
453
+ * `expiresAtMs: number` – epoch time (in milliseconds) for when the token will expire
454
+ * `expiresInMs?: number` – Optional; milliseconds for how long the token is valid for (default 691199000)
455
+ * `timeframe?: number` – Optional; timeframe (in milliseconds) to check if the token was issued within
456
+ * `startTime?: number` – Optional; time to count `timeframe` back from (in epoch time). Default is `Date.now()`
457
+
458
+ Returns: boolean of whether the token was issued within the given timeframe (from now)
459
+
460
+ ## Limitations
461
+ 1. Most browsers will not allow the redirect app to close the window. They will log: `Scripts may close only the windows that were opened by them.` to the console and keep the window open.
3
462
 
4
- ### Limitations
5
- * cannot use popup auth in private/incognito mode – localStorage is not shared
463
+ ## TODO
464
+ Need to add an "storage_key_expires_at" and then clean those up. So there aren't tons of `gc-ca_{uuid}`s in localStorage.