genesys-cloud-client-auth 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,17 +1,474 @@
1
- # Genesys Cloud Client Auth #
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)
2
5
 
3
- This project is a Bitbucket repository that contains the pipeline infrastructure for the open source [Genesys Cloud Client Auth library](https://github.com/MyPureCloud/genesys-cloud-client-auth) hosted on GitHub.
6
+ # genesys-cloud-client-auth
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.
4
9
 
5
- ### What is this repository for?
10
+ * [Install](#install)
11
+ * [Usage](#usage)
12
+ * [Standard Usage](#usage)
13
+ * [Popup Authentication (for Iframes)](#popup-auth)
14
+ * [API](#api)
15
+ * [Limitations](#limitations)
6
16
 
7
- Current guidance from security and the CI/CD teams is to not have the pipeline infrastructure available in open source repositories. This repository is used to host the pipeline infrastructure for the Genesys Cloud Client Auth library so that we may retain access to the CDN and ability to publish to NPM.
8
17
 
9
- ### Contributions
18
+ ## Install
19
+ ``` sh
20
+ npm add genesys-cloud-client-auth
21
+ # or
22
+ yarn add genesys-cloud-client-auth
23
+ ```
10
24
 
11
- * Leave all source code in the GitHub repository.
12
- * Only pipeline infrastructure should be in this repository.
25
+ Or you can download directly from the browser:
13
26
 
14
- ### Who do I talk to?
27
+ > NOTE: that since v1.0.0, you must specify the major version to download from the CDN. See v1.0.0's **BREAKING CHANGES** in the `CHANGELOG.md` for more details.
15
28
 
16
- * gcmediastreamsignal@genesys.com
17
- * Client Signaling and Streaming Team (STREAM).
29
+ ``` html
30
+ <!-- change out the domain if desired -->
31
+ <script src="https://apps.mypurecloud.com/client-auth/v1/genesys-cloud-client-auth.browser.min.js"></script>
32
+ ```
33
+
34
+ ## Usage
35
+ ``` typescript
36
+ import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
37
+
38
+ const clientId = 'Your Oauth ClientID';
39
+ const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
40
+ environment: 'mypurecloud.com',
41
+ persist: false,
42
+ storageKey: 'gc_client_auth_data',
43
+ debugMode: false,
44
+ customHeaders: {
45
+ 'X-My-Header': 'value'
46
+ }
47
+ });
48
+
49
+ authenticator.loginImplicitGrant({
50
+ redirectUri: 'https://myapp.example.com/app/', // whatever valid redirect URI is configured for your Oauth client
51
+ state: '', // optional state to return after authentication
52
+ /* All optional – see the advanced usage and/or API section for these – defaults listed below */
53
+ org: '',
54
+ provider: '',
55
+ usePopupAuth: false,
56
+ popupTimeout: 15000
57
+ }).then((data: IAuthData) => {
58
+ /* data will contain authentication information like accessToken */
59
+ }).catch(error => {
60
+ /* authentication failed */
61
+ });
62
+ ```
63
+
64
+ ## Popup Auth
65
+ 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.
66
+
67
+ #### Auth Flow Using Popup
68
+
69
+ ```
70
+ Iframed App Redirect App Login
71
+ | | |
72
+ |------- (1) -------------------------->|
73
+ | | |
74
+ | |<------ (2) ------|
75
+ | | |
76
+ |<------ (3) --------| |
77
+ ```
78
+
79
+ 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.
80
+ 1. Once authenticated, the login page will redirect to the "Redirect App" (more on this below).
81
+ 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.
82
+
83
+ > 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.
84
+
85
+ #### Popup Auth Usage
86
+ ``` typescript
87
+ import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
88
+
89
+ const clientId = 'Your Oauth ClientID';
90
+ const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
91
+ environment: 'mypurecloud.com',
92
+ persist: true, // this is required to use popup auth
93
+ storageKey: 'gc_client_auth_data',
94
+ debugMode: false // setting to `true` for popup auth will help with debugging
95
+ });
96
+
97
+ authenticator.loginImplicitGrant({
98
+ // if left falsy, the `https://apps.{env}/client-auth/` app will be used for the redirectUri
99
+ // else, your redirect will need to implement the parsing of the token (see next step)
100
+ redirectUri: 'https://myapp.example.com/app/',
101
+ usePopupAuth: true,
102
+ popupTimeout: 15000 // default amount
103
+ }).then((data: IAuthData) => {
104
+ /* data will contain authentication information like accessToken */
105
+ }).catch(error => {
106
+ /* authentication failed */
107
+ if (error.name === 'TIMEOUT_ERROR') {
108
+ // this error will trigger after the `popupTimeout` expires without valid auth data saved
109
+ // this could be an indication that the user has popups blocked
110
+ // you will need to add application logic to handle these errors
111
+ }
112
+ });
113
+ ```
114
+
115
+ 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:
116
+
117
+ ``` typescript
118
+ import { handleRedirectFromLogin } from 'genesys-cloud-client-auth';
119
+
120
+ try {
121
+ // this will parse and save auth data to localStorage
122
+ handleRedirectFromLogin();
123
+ } catch (error) {
124
+ // it could error for multiple reasons.
125
+ // mainly, if the auth hash is not present
126
+ // or if there is no storage ID as the state field
127
+ }
128
+ ```
129
+
130
+ It can also be used directly in the HTML:
131
+
132
+ ``` html
133
+ <script src="https://apps.mypurecloud.com/client-auth/v1/genesys-cloud-client-auth.browser.min.js"></script>
134
+ <script>
135
+ try {
136
+ GenesysCloudClientAuth.handleRedirectFromLogin();
137
+ console.log('Successfully parsed params from hash');
138
+ } catch (error) {
139
+ console.warn(`Error parsing auth params from hash – ${error.name}: "${error.message}"`);
140
+ }
141
+ </script>
142
+ ```
143
+
144
+ The `redirectUri` is very important here. There are two options:
145
+ 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.
146
+ 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).
147
+
148
+ ## API
149
+
150
+ ### `authenticatorFactory()`
151
+ Factory function to generate a singleton instance of a ClientAuthenticator class.
152
+ If an instance has already been created for passed in `clientId`, that instance
153
+ will be returned _without_ updating the original configuration.
154
+
155
+ Declaration:
156
+ ``` ts
157
+ authenticatorFactory: (clientId: string, config: Partial<IAuthenticatorConfig>) => GenesysCloudClientAuthenticator;
158
+ ```
159
+
160
+ Params:
161
+ * `client: string` – Oauth Client ID
162
+ * `config: Partial<IAuthenticatorConfig>` – Optional; configuration for the ClientAuthenticator instance. Available options (with defaults):
163
+ ``` ts
164
+ interface IAuthenticatorConfig {
165
+ /**
166
+ * Genesys Cloud domain.
167
+ * Defaults to: `'mypurecloud.com'`
168
+ */
169
+ environment: string;
170
+
171
+ /**
172
+ * Persist authentication data to localStorage.
173
+ * Note: this is required if using popup authentication
174
+ * Defaults to: `false`
175
+ */
176
+ persist: boolean;
177
+
178
+ /**
179
+ * Storage key to save auth data to localStorage.
180
+ * Defaults to: `gc_client_auth_data`
181
+ */
182
+ storageKey: string;
183
+
184
+ /**
185
+ * Allow for extra console logs for debugging
186
+ * Defaults to: `false`
187
+ */
188
+ debugMode: boolean;
189
+
190
+ /**
191
+ * Custom headers to include in all API requests.
192
+ * Example: { 'X-My-Header': 'value' }
193
+ */
194
+ customHeaders?: Record<string, string>;
195
+ }
196
+ ```
197
+
198
+ Returns: Singleton GenesysCloudClientAuthenticator instance
199
+
200
+ ### GenesysCloudClientAuthenticator
201
+ Class to manage authentication and state. It is recommended to use the `authenticatorFactory` to construct a singleton instance of this class.
202
+
203
+ #### Properties
204
+
205
+ ##### `authenticator.clientId`
206
+ Oauth client id
207
+
208
+ ##### `authenticator.VERSION`
209
+ client-auth version
210
+
211
+ ##### `authenticator.authData`
212
+ current authencation data for this instance. default is an empty object `{}`. Definition:
213
+ ``` ts
214
+ interface IAuthData {
215
+ /** access token received from login */
216
+ accessToken?: string;
217
+ /** optional state returned from login */
218
+ state?: string;
219
+ /** time at which the token expires */
220
+ tokenExpiryTime?: number;
221
+ /** time at which the token expires in ISO string format */
222
+ tokenExpiryTimeString?: string;
223
+ /** error that may have occurred during login */
224
+ error?: string;
225
+ /** error description that may have occurred during login */
226
+ error_description?: string;
227
+ }
228
+ ```
229
+
230
+ ##### `authenticator.config`
231
+ current configuration for this instance
232
+
233
+ ##### `authenticator.environment`
234
+ current environment. Ex. `mypurecloud.com`.
235
+ > Note: do not update this property individually. Use `authenticator.setEnvironment(env: string)` if updating it is necessary.
236
+
237
+ ##### `authenticator.basePath`
238
+ base api path – utilizing the `environment` varialbe
239
+
240
+ ##### `authenticator.authUrl`
241
+ base auth path – utilizing the `environment` varialbe
242
+
243
+ #### Methods
244
+
245
+ ##### `constructor()`
246
+ Construct a new Authenticator instance. It is recommended you use the `authenticatorFactory()` to construct a singleton for each necessary Oauth client.
247
+
248
+ Declaration:
249
+ ``` ts
250
+ constructor (clientId: string, config: Partial<IAuthenticatorConfig> = {});
251
+ ```
252
+
253
+ Params:
254
+ * `client: string` – Oauth Client ID
255
+ * `config: Partial<IAuthenticatorConfig>` – Optional; configuration for the ClientAuthenticator instance. See [authenticatorFactory()](#authenticatorfactory) for more details.
256
+
257
+ Returns: `GenesysCloudClientAuthenticator` instance
258
+
259
+ ##### `authenticator.loginImplicitGrant()`
260
+ Initiates the implicit grant login flow. Will attempt to load the token from local storage, if enabled.
261
+
262
+ Declaration:
263
+ ``` ts
264
+ loginImplicitGrant(opts?: ILoginOptions, existingAuthData?: IAuthData): Promise<IAuthData | undefined>;
265
+ ```
266
+
267
+ Params:
268
+ * `opts: ILoginOptions` – Options to login with
269
+ ``` ts
270
+ interface ILoginOptions {
271
+ /**
272
+ * The redirect URI of the OAuth Implicit Grant client. Not needed if `usePopupAuth: true` _and_
273
+ * the consuming application wishes to use the standard redirect of genesys-cloud-client-auth
274
+ * standalone app.
275
+ */
276
+ redirectUri?: string;
277
+ /**
278
+ * Any state needed when returning from login
279
+ */
280
+ state?: string;
281
+ /**
282
+ * The organization name that would normally used when specifying an organization name when logging in.
283
+ * This is only used when a provider is also specified.
284
+ */
285
+ org?: string;
286
+ /**
287
+ * Authentication provider to log in with e.g. okta, adfs, salesforce, onelogin.
288
+ * This is only used when an org is also specified.
289
+ */
290
+ provider?: string;
291
+ /**
292
+ * Use a popup window to open to the login page.
293
+ */
294
+ usePopupAuth?: boolean;
295
+ /**
296
+ * Timeout for how long the auth pop should remain open before timing out
297
+ * and rejecting the loginImplicitGrant call. This is only used in conjunction
298
+ * with `usePopupAuth`.
299
+ */
300
+ popupTimeout?: number;
301
+ }
302
+ ```
303
+ * `existingAuthData?: IAuthData` – Optional; authentication data to use. default will be parsed from url hash
304
+
305
+ Returns: promise containing `IAuthData` (see [authenticator.authData](#authenticator.authData) for definition)
306
+
307
+ ##### `authenticator.setEnvironment()`
308
+ Sets the environment, baseUrl, and authUrl used by the session
309
+
310
+ Declaration:
311
+ ``` ts
312
+ setEnvironment(environment?: string): void;
313
+ ```
314
+
315
+ Params:
316
+ * `environment?: string` –  (Optional, default "mypurecloud.com") Environment the instance uses, e.g. mypurecloud.ie, mypurecloud.com.au, etc.
317
+
318
+ Returns: void
319
+
320
+ ##### `authenticator.clearAuthData()`
321
+ Will clear current auth data from localStorage.
322
+
323
+ > NOTE: this will _not_ log the user out. Using `logout()`
324
+ for logging out
325
+
326
+ Declaration:
327
+ ``` ts
328
+ clearAuthData(): void;
329
+ ```
330
+
331
+ Params: none
332
+
333
+ Returns: void
334
+
335
+ ##### `authenticator.logout()`
336
+ Clears auth data from localStorage and redirects the user to the GenesysCloud logout page
337
+
338
+ Declaration:
339
+ ``` ts
340
+ logout(logoutRedirectUri?: string): void;
341
+ ```
342
+
343
+ Params:
344
+ * `logoutRedirectUri?: string` – Optional, redirectUri to pass to the logout page
345
+
346
+ Returns: void
347
+
348
+ ##### `authenticator.setAccessToken()`
349
+ Sets the access token on the authenticator instance and localStorage (if configured)
350
+
351
+ Declaration:
352
+ ``` ts
353
+ setAccessToken(token: string): void;
354
+ ```
355
+
356
+ Params:
357
+ * `token: string` – The access token
358
+
359
+ Returns: void
360
+
361
+ ##### `authenticator.testAccessToken()`
362
+ Test an accessToken by using it to make an API call. It will resolve
363
+ if the token is valid, and will reject if it is not valid.
364
+
365
+ Declaration:
366
+ ``` ts
367
+ testAccessToken(token: string): Promise<any>;
368
+ ```
369
+
370
+ Params:
371
+ * `token: string` – accessToken to test
372
+
373
+ Returns: promise that will resolve or reject depending on the validity of the token passed in
374
+
375
+ ##### `authenticator.parseDate()`
376
+ Parses an ISO-8601 string representation of a date value.
377
+
378
+ Declaration:
379
+ ``` ts
380
+ parseDate (str: string): Date;
381
+ ```
382
+
383
+ Params:
384
+ * `str: string` – The date value as a string.
385
+
386
+ Returns: The parsed date object.
387
+
388
+ ### `handleRedirectFromLogin()`
389
+ Helper function to parse the auth data opened from a popup authentication window.
390
+ It will save the auth data to localStorage.
391
+
392
+ > Note: this will throw errors if it cannot parse or save the data correctly
393
+
394
+ Declaration:
395
+ ``` ts
396
+ handleRedirectFromLogin: () => void;
397
+ ```
398
+
399
+ Params: none
400
+
401
+ Returns: void
402
+
403
+ ### `Utils`
404
+ Utility functions to supplement and extend usage.
405
+
406
+ #### `utils.parseOauthParams()`
407
+ Utility to parse the auth data returned from the login page and return
408
+ authentication data as an object.
409
+
410
+ > Note: this will throw errors if it cannot parse or save the data correctly
411
+
412
+ Declaration:
413
+ ``` ts
414
+ parseOauthParams: (hash?: string): IAuthData;
415
+ ```
416
+
417
+ Params:
418
+ * `hash?: string` – Optional; hash to parse (default `window.location.hash`)
419
+
420
+ Returns: authentication data parsed from the passed in hash
421
+
422
+ #### `utils.tokenWasIssuedAt()`
423
+ Determine when a token was issued at by subtracting the validity
424
+ time from the expires at time.
425
+
426
+ Declaration:
427
+ ``` ts
428
+ tokenWasIssuedAt (expiresAtMs: number, expiresInMs: number): number;
429
+ ```
430
+
431
+ Params:
432
+ * `expiresAtMs: number` – epoch time (in milliseconds) for when the token will expire
433
+ * `expiresInMs: number` – milliseconds for how long the token is valid for
434
+
435
+ Returns: milliseconds since epoch time
436
+
437
+ #### `utils.isIssuedTimeWithinTimeframe()`
438
+ Determine if a token was issued within a given timeframe window. Example may be:
439
+ a token is received (either from localStorage or some other way) and you need
440
+ to be able to tell if it was issued within the last 10 minutes. Use this function
441
+ as follows:
442
+
443
+ ``` ts
444
+ const tokenExpiryTime = 1624611600000; // "2021-06-25 09:00.000Z"
445
+ const tokenExpiresIn = 86400000; // 1 day: meaning token was issuedAt "2021-06-24 09:00.000Z"
446
+ const timeframe = 600000; // 10 minutes
447
+ const startTime = 1624525260000; // "2021-06-24 09:01.000Z": 1 minute after issued time
448
+
449
+ const willBeTrue = isIssuedTimeWithinTimeframe(
450
+ tokenExpiryTime,
451
+ tokenExpiresIn,
452
+ timeframe,
453
+ startTime
454
+ );
455
+ ```
456
+
457
+ Declaration:
458
+ ``` ts
459
+ isIssuedTimeWithinTimeframe: (expiresAtMs: number, expiresInMs?: number, timeframe?: number, startTime?: number) => boolean;
460
+ ```
461
+
462
+ Params:
463
+ * `expiresAtMs: number` – epoch time (in milliseconds) for when the token will expire
464
+ * `expiresInMs?: number` – Optional; milliseconds for how long the token is valid for (default 691199000)
465
+ * `timeframe?: number` – Optional; timeframe (in milliseconds) to check if the token was issued within
466
+ * `startTime?: number` – Optional; time to count `timeframe` back from (in epoch time). Default is `Date.now()`
467
+
468
+ Returns: boolean of whether the token was issued within the given timeframe (from now)
469
+
470
+ ## Limitations
471
+ 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.
472
+
473
+ ## TODO
474
+ 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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "1.0.1",
3
- "build": "2",
4
- "buildDate": "2025-07-29T15:39:29.003Z",
2
+ "version": "1.0.2",
3
+ "build": "4",
4
+ "buildDate": "2026-04-28T17:34:58.492Z",
5
5
  "indexFiles": [
6
6
  {
7
7
  "file": "index.html"
@@ -10,7 +10,7 @@
10
10
  "file": "/v1/genesys-cloud-client-auth.browser.min.js"
11
11
  },
12
12
  {
13
- "file": "/v1.0.1/genesys-cloud-client-auth.browser.min.js"
13
+ "file": "/v1.0.2/genesys-cloud-client-auth.browser.min.js"
14
14
  }
15
15
  ],
16
16
  "team": "Client Streaming and Signaling",