genesys-cloud-client-auth
Small, lightweight library and app to handle authentication for client applications. Big advantage is utilization of popup windows to authenticate apps within iframes.
This library only supports implicit logins for use within a front-end web application.
Install
npm add genesys-cloud-client-auth
yarn add genesys-cloud-client-auth
Or you can download directly from the browser:
<script src="https://apps.mypurecloud.com/client-auth/genesys-cloud-client-auth.browser.min.js"></script>
Usage
import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
const clientId = 'Your Oauth ClientID';
const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
environment: 'mypurecloud.com',
persist: false,
storageKey: 'gc_client_auth_data',
debugMode: false
});
authenticator.loginImplicitGrant({
redirectUri: 'https://myapp.example.com/app/',
state: '',
org: '',
provider: '',
usePopupAuth: false,
popupTimeout: 15000
}).then((data: IAuthData) => {
}).catch(error => {
});
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.
Iframed App Redirect App Login
| | |
|------- (1) -------------------------->|
| | |
| |<------ (2) ------|
| | |
|<------ (3) --------| |
- 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.
- Once authenticated, the login page will redirect to the "Redirect App" (more on this below).
- 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.
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.
import { GenesysCloudClientAuthenticator, authenticatorFactory, IAuthData } from 'genesys-cloud-client-auth';
const clientId = 'Your Oauth ClientID';
const authenticator: GenesysCloudClientAuthenticator = authenticatorFactory(clientId, {
environment: 'mypurecloud.com',
persist: true,
storageKey: 'gc_client_auth_data',
debugMode: false
});
authenticator.loginImplicitGrant({
redirectUri: 'https://myapp.example.com/app/',
usePopupAuth: true,
popupTimeout: 15000
}).then((data: IAuthData) => {
}).catch(error => {
if (error.name === 'TIMEOUT_ERROR') {
}
});
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:
import { handleRedirectFromLogin } from 'genesys-cloud-client-auth';
try {
handleRedirectFromLogin();
} catch (error) {
}
It can also be used directly in the HTML:
<script src="https://apps.mypurecloud.com/client-auth/genesys-cloud-client-auth.browser.min.js"></script>
<script>
try {
GenesysCloudClientAuth.handleRedirectFromLogin();
console.log('Successfully parsed params from hash');
} catch (error) {
console.warn(`Error parsing auth params from hash – ${error.name}: "${error.message}"`);
}
</script>
The redirectUri
is very important here. There are two options:
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.
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).
API
authenticatorFactory()
Factory function to generate a singleton instance of a ClientAuthenticator class.
If an instance has already been created for passed in clientId
, that instance
will be returned without updating the original configuration.
Declaration:
authenticatorFactory: (clientId: string, config: Partial<IAuthenticatorConfig>) => GenesysCloudClientAuthenticator;
Params:
Returns: Singleton GenesysCloudClientAuthenticator instance
GenesysCloudClientAuthenticator
Class to manage authentication and state. It is recommended to use the authenticatorFactory
to construct a singleton instance of this class.
Properties
authenticator.clientId
Oauth client id
authenticator.VERSION
client-auth version
authenticator.authData
current authencation data for this instance. default is an empty object {}
. Definition:
interface IAuthData {
accessToken?: string;
state?: string;
tokenExpiryTime?: number;
tokenExpiryTimeString?: string;
error?: string;
error_description?: string;
}
authenticator.config
current configuration for this instance
authenticator.environment
current environment. Ex. mypurecloud.com
.
Note: do not update this property individually. Use authenticator.setEnvironment(env: string)
if updating it is necessary.
authenticator.basePath
base api path – utilizing the environment
varialbe
authenticator.authUrl
base auth path – utilizing the environment
varialbe
Methods
constructor()
Construct a new Authenticator instance. It is recommended you use the authenticatorFactory()
to construct a singleton for each necessary Oauth client.
Declaration:
constructor (clientId: string, config: Partial<IAuthenticatorConfig> = {});
Params:
client: string
– Oauth Client IDconfig: Partial<IAuthenticatorConfig>
– Optional; configuration for the ClientAuthenticator instance. See authenticatorFactory() for more details.
Returns: GenesysCloudClientAuthenticator
instance
authenticator.loginImplicitGrant()
Initiates the implicit grant login flow. Will attempt to load the token from local storage, if enabled.
Declaration:
loginImplicitGrant(opts?: ILoginOptions, existingAuthData?: IAuthData): Promise<IAuthData | undefined>;
Params:
Returns: promise containing IAuthData
(see authenticator.authData for definition)
authenticator.setEnvironment()
Sets the environment, baseUrl, and authUrl used by the session
Declaration:
setEnvironment(environment?: string): void;
Params:
environment?: string
– (Optional, default "mypurecloud.com") Environment the instance uses, e.g. mypurecloud.ie, mypurecloud.com.au, etc.
Returns: void
authenticator.clearAuthData()
Will clear current auth data from localStorage.
NOTE: this will not log the user out. Using logout()
for logging out
Declaration:
clearAuthData(): void;
Params: none
Returns: void
authenticator.logout()
Clears auth data from localStorage and redirects the user to the GenesysCloud logout page
Declaration:
logout(logoutRedirectUri?: string): void;
Params:
logoutRedirectUri?: string
– Optional, redirectUri to pass to the logout page
Returns: void
authenticator.setAccessToken()
Sets the access token on the authenticator instance and localStorage (if configured)
Declaration:
setAccessToken(token: string): void;
Params:
token: string
– The access token
Returns: void
authenticator.testAccessToken()
Test an accessToken by using it to make an API call. It will resolve
if the token is valid, and will reject if it is not valid.
Declaration:
testAccessToken(token: string): Promise<any>;
Params:
token: string
– accessToken to test
Returns: promise that will resolve or reject depending on the validity of the token passed in
authenticator.parseDate()
Parses an ISO-8601 string representation of a date value.
Declaration:
parseDate (str: string): Date;
Params:
str: string
– The date value as a string.
Returns: The parsed date object.
handleRedirectFromLogin()
Helper function to parse the auth data opened from a popup authentication window.
It will save the auth data to localStorage.
Note: this will throw errors if it cannot parse or save the data correctly
Declaration:
handleRedirectFromLogin: () => void;
Params: none
Returns: void
Utils
Utility functions to supplement and extend usage.
utils.parseOauthParams()
Utility to parse the auth data returned from the login page and return
authentication data as an object.
Note: this will throw errors if it cannot parse or save the data correctly
Declaration:
parseOauthParams: (hash?: string): IAuthData;
Params:
hash?: string
– Optional; hash to parse (default window.location.hash
)
Returns: authentication data parsed from the passed in hash
utils.tokenWasIssuedAt()
Determine when a token was issued at by subtracting the validity
time from the expires at time.
Declaration:
tokenWasIssuedAt (expiresAtMs: number, expiresInMs: number): number;
Params:
expiresAtMs: number
– epoch time (in milliseconds) for when the token will expireexpiresInMs: number
– milliseconds for how long the token is valid for
Returns: milliseconds since epoch time
utils.isIssuedTimeWithinTimeframe()
Determine if a token was issued within a given timeframe window. Example may be:
a token is received (either from localStorage or some other way) and you need
to be able to tell if it was issued within the last 10 minutes. Use this function
as follows:
const tokenExpiryTime = 1624611600000;
const tokenExpiresIn = 86400000;
const timeframe = 600000;
const startTime = 1624525260000;
const willBeTrue = isIssuedTimeWithinTimeframe(
tokenExpiryTime,
tokenExpiresIn,
timeframe,
startTime
);
Declaration:
isIssuedTimeWithinTimeframe: (expiresAtMs: number, expiresInMs?: number, timeframe?: number, startTime?: number) => boolean;
Params:
expiresAtMs: number
– epoch time (in milliseconds) for when the token will expireexpiresInMs?: number
– Optional; milliseconds for how long the token is valid for (default 691199000)timeframe?: number
– Optional; timeframe (in milliseconds) to check if the token was issued withinstartTime?: number
– Optional; time to count timeframe
back from (in epoch time). Default is Date.now()
Returns: boolean of whether the token was issued within the given timeframe (from now)
Limitations
- 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.
TODO
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.