NodeJS library for Webmessaging Authentication

hi ,

If anyone can advise, just wondering if we can implement https://developer.genesys.cloud/commdigital/digital/webmessaging/messengersdk/SDKCommandsEvents

with Node.JS, if yes what library we can use ?

Genesys('registerPlugin', 'AuthProvider', (AuthProvider) => {

// COMMAND
// *********
// getAuthCode
// reAuthenticate

/* Register Command - mandatory */

AuthProvider.registerCommand('getAuthCode', (e) => {

// Add the necessary logic and resolve with the authCode and redirectUri provided by your Authentication provider. Messenger will call this command to get the the tokens.

e.resolve({
	authCode: <brand auth code>,       // pass your authorization code here
	redirectUri: <your redirect uri>,  // pass the redirection URI configured in your Authentication provider here
	nonce: <your nonce>,               // pass the random string preferably in uuid format. Applicable for OKTA provider.
	maxAge: <your maxAge>,             // pass elapsed time in seconds. Applicable for OKTA provider and it is an optional parameter.
	codeVerifier: <your code verifier> // pass your code verifier here when PKCE flow is enabled
});

});

AuthProvider.registerCommand('reAuthenticate', (e) => {

// Messenger will call this command when current refreshToken and/or authCode are no more valid. Brand can add logic here to simply re-login and resolve this command after successful login so that Messenger can get the new authCode. (In case when browser needs to reload for a login, there is no need to resolve this command). Note: After a successful re-login, calling the getAuthCode command is taken care internally and there is no need to call it explicitly again.

document.getElementById('myLoginButton').click(); // simulate the login button click
e.resolve();

});

thanks
Fransiska

Hello Fransiska,
Can you help us clarify what you are trying to solve with the NodeJS approach?

hi Angelo,

Reason I am using node.Js because according https://developer.genesys.cloud/blueprints/messenger-authentication-okta-integration-blueprint/


javascript app need be set as Web Application, and not SPA, and we can not set redirectURI is same with login URI (that only can be applied in SPA).

So this is my current javascript (which giving error, that i then thinking to use node.js)

<script>
    (function (g, e, n, es, ys) {
        g['_genesysJs'] = e;
        g[e] = g[e] || function () {
          (g[e].q = g[e].q || []).push(arguments)
        };
        g[e].t = 1 * new Date();
        g[e].c = es;
        ys = document.createElement('script'); ys.async = 1; ys.src = n; ys.charset = 'utf-8'; document.head.appendChild(ys);
      })(window, 'Genesys', 'https://apps.mypurecloud.com.au/genesys-bootstrap/genesys.min.js', {
        environment: 'apse2',
        deploymentId: 'ddaaa095-d54d-4bb9-b596-9f9beed01dd3'
      });
</script>

<script>

    const oktaConfig = {
        redirectUri: 'https://devsql.veridian.com.au/crm/purecloud/auth.html',
        postLogoutRedirectUri: 'https://devsql.veridian.com.au',
        clientId: '0oa1bu48dh5brPuvK0h8',
        issuer: 'https://dev-495736.oktapreview.com/oauth2/default',
        scopes: ['openid', 'email', 'profile', 'offline_access'],
        pkce: false,
        responseType: 'code',
        maxAge : 86400
    };
    const authClient = new OktaAuth(oktaConfig);

    (function() {

        let oktaTransactionStorage = window.sessionStorage.getItem("okta-transaction-storage"); // Get 'okta-transaction-storage' value from session storage
        //alert(oktaTransactionStorage);
        if (oktaTransactionStorage) {
            const storage = JSON.parse(oktaTransactionStorage); // Convert text in 'oktaTransactionStorage' to javascript object
    
            if (storage && Object.keys(storage).length) { // If 'storage' is present destructure nonce from 'storage'
                const { nonce } = storage || {};
            }
        }

        var url =window.location.href;

        if(url.indexOf('code')>-1){
            
            Genesys('registerPlugin', 'AuthProvider', (AuthProvider) => {
                let oktaTransactionStorage = window.document.cookie.toString(); // Get nonce from cookie
                let nonce1='';
                if (oktaTransactionStorage) {
                    const storage = oktaTransactionStorage.split('okta-oauth-nonce=')[1]; // Extract 'okta-oauth-nonce' cookie from 'oktaTransactionStorage'
                    nonce1 = storage.split(';')[0];
                }

                const urlParams = new URLSearchParams(window.location.search); // Get the authorization response which is added as a query string from the redirect URL
                const authCode1 = urlParams.has('code') ? urlParams.get('code'): '';// Get code from the query string
                var codeVerif=JSON.parse(window.sessionStorage.getItem("okta-transaction-storage")).codeVerifier;
  

                AuthProvider.registerCommand('getAuthCode', (e) => {
                    e.resolve({
                        authCode: authCode1,      // Pass your authCode here
                        redirectUri: 'https://devsql.veridian.com.au/crm/purecloud/auth.html',     // Pass the redirection URI configured in your authentication provider here
                        nonce: nonce1,        //  Mandatory parameter in OKTA Javascript SDK approach.
                        maxAge: 86400,        // Pass the elapsed time in seconds as an optional parameter
                        codeVerifier: codeVerif   // For PKCE Oauth flow: If you use the Okta Auth JavaScript SDK to authenticate signin, get the code verifier from session storage. If you use the endpoint to authenticate signin, pass a cryptographically random string that you used to generate the codeChallenge value.
                    });
                });

                AuthProvider.subscribe('Auth.ready', (res) => {
        //bAuthenticated = AuthProvider.data('Auth.authenticated');
        console.log('AUTH READY');
        console.log(res);
        });

                AuthProvider.subscribe('Auth.authenticated', (res) => {
                        console.log('Auth.authenticated');
                        console.log(res);
                });

                AuthProvider.subscribe('Auth.error', (error) => {
                        console.log('Auth.error');
                        console.log(error);
                });

                AuthProvider.subscribe('Auth.authError', (error) => {
                    console.log("Auth.authError", error);
                    console.log(error);
                });

                AuthProvider.ready();
            });
        }
        else{
            authClient.signInWithRedirect({
                originalUri:'https://devsql.veridian.com.au/crm/purecloud/auth.html',
                ...oktaConfig
            });
        }

    })(); 

So basically :

    const oktaConfig = {
        redirectUri: 'https://devsql.veridian.com.au/crm/purecloud/auth.html',
        postLogoutRedirectUri: 'https://devsql.veridian.com.au',
        clientId: '0oa1bu48dh5brPuvK0h8',
        issuer: 'https://dev-495736.oktapreview.com/oauth2/default',
        scopes: ['openid', 'email', 'profile', 'offline_access'],
        pkce: false,
        responseType: 'code',
        maxAge : 86400
    };
    const authClient = new OktaAuth(oktaConfig);

 authClient.signInWithRedirect({
                originalUri:'https://devsql.veridian.com.au/crm/purecloud/auth.html',
                ...oktaConfig
  });

 Once redirected, I got following response in URL: 

 https://devsql.veridian.com.au/crm/purecloud/auth.html?code=8vESV0pUnYt_Ijwim8xZbEl2r4H_NeZqDhhDiT5oil4&state=QEDIhL9ClkPZkiKM7cweVJbJw5yjLZdd65Ao9iiIsewCydyUO699oahNF7IA9IcN

and run getAuth code as following:

            Genesys('registerPlugin', 'AuthProvider', (AuthProvider) => {
                let oktaTransactionStorage = window.document.cookie.toString(); // Get nonce from cookie
                let nonce1='';
                if (oktaTransactionStorage) {
                    const storage = oktaTransactionStorage.split('okta-oauth-nonce=')[1]; // Extract 'okta-oauth-nonce' cookie from 'oktaTransactionStorage'
                    nonce1 = storage.split(';')[0];
                }

                const urlParams = new URLSearchParams(window.location.search); // Get the authorization response which is added as a query string from the redirect URL
                const authCode1 = urlParams.has('code') ? urlParams.get('code'): '';// Get code from the query string
                var codeVerif=JSON.parse(window.sessionStorage.getItem("okta-transaction-storage")).codeVerifier;
                              

                AuthProvider.registerCommand('getAuthCode', (e) => {
                    e.resolve({
                        authCode: authCode1,   
                        redirectUri: 'https://devsql.veridian.com.au/crm/purecloud/auth.html',     
                        nonce: nonce1
                        maxAge: 86400,
                        codeVerifier: codeVerif  
                    });
                });


                AuthProvider.subscribe('Auth.ready', (res) => {
                            console.log('AUTH READY');
                            console.log(res);
               });

                AuthProvider.subscribe('Auth.authenticated', (res) => {
                        console.log('Auth.authenticated');
                        console.log(res);
                });

                AuthProvider.subscribe('Auth.error', (error) => {
                        console.log('Auth.error');
                        console.log(error);
                });

                AuthProvider.subscribe('Auth.authError', (error) => {
                    console.log("Auth.authError", error);
                    console.log(error);
                });

                AuthProvider.ready();
            });

But Auth.error:

The alternative way is using:

So authURL is

authURL = 'https://dev-495736.oktapreview.com/oauth2/v1/authorize?client_id=0oa1bu48dh5brPuvK0h8&scope=openid%20email%20profile%20offline_access&response_type=code&redirect_uri=https://devsql.veridian.com.au/crm/purecloud/auth.html&state=eyJiYWNrVG9QYXRoIjoiL3ByaXZhdGUiLCJpc3N1ZXIiOiJva3RhIiwiYnl0ZXMiOiItSEhlWEV3YmNRak5fQWl3a0NkanVDNEZpQ1VPRV81emkzeFlKa1BQaWcwIn0%3D';

and I just do redirect as following:

window.location.href =authURL;

Question is where I can get state value ? state=eyJiYWNrVG9QYXRoIjoiL3ByaXZhdGUiLCJpc3N1ZXIiOiJva3RhIiwiYnl0ZXMiOiItSEhlWEV3YmNRak5fQWl3a0NkanVDNEZpQ1VPRV81emkzeFlKa1BQaWcwIn0%3D'

Do I still need to do following script in the first place to get state ?

 authClient.signInWithRedirect({
                originalUri:'https://devsql.veridian.com.au/crm/purecloud/auth.html',
                ...oktaConfig
  });

Please advise.

Thanks
Fransiska

hi Angelo,

I just created standard JavaScript for this:

<script>
          (function (g, e, n, es, ys) {
              g['_genesysJs'] = e;
              g[e] = g[e] || function () {
                (g[e].q = g[e].q || []).push(arguments)
              };
              g[e].t = 1 * new Date();
              g[e].c = es;
              ys = document.createElement('script'); ys.async = 1; ys.src = n; ys.charset = 'utf-8'; document.head.appendChild(ys);
            })(window, 'Genesys', 'https://apps.mypurecloud.com.au/genesys-bootstrap/genesys.min.js', {
              environment: 'apse2',
              deploymentId: 'ddaaa095-d54d-4bb9-b596-9f9beed01dd3'
            });
</script>

<script>

  function generateCodeVerifier(length) {
            let text = '';
            const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
            for (let i = 0; i < length; i++) {
                text += possible.charAt(Math.floor(Math.random() * possible.length));
            }
            return text;
   }


  const oktaConfig = {
          redirectUri: 'http://localhost',
          postLogoutRedirectUri: 'http://localhost',
          clientId: '0oa6bfvjuz2uGGI4e5d7',
          issuer: 'https://dev-15132560.okta.com',
          scopes: ['openid', 'email', 'profile', 'offline_access'],
          pkce: false,
          responseType: 'code',
          maxAge : 86400
  };
  const authClient = new OktaAuth(oktaConfig);

  (function() {

      Genesys('registerPlugin', 'AuthProvider', (AuthProvider) => {

        var url =window.location.href;
                if(url.indexOf('code')<=-1){
                  authClient.signInWithRedirect({
                      originalUri:'http://localhost',
                      ...oktaConfig
                  });
                }
                else {
                  let oktaTransactionStorage = window.document.cookie.toString(); // Get nonce from cookie

                  var nonce1='';
                  if (oktaTransactionStorage) {
                    const storage = oktaTransactionStorage.split('okta-oauth-nonce=')[1]; // Extract 'okta-oauth-nonce' cookie from 'oktaTransactionStorage'
                    nonce1= storage.split(';')[0];
                  }

                  const urlParams = new URLSearchParams(window.location.search); // Get the authorization response which is added as a query string from the redirect URL
                  const authCode1 = urlParams.has('code') ? urlParams.get('code'):''; // Get code from the query string
                  var codeVerif=JSON.parse(window.sessionStorage.getItem("okta-transaction-storage")).codeVerifier;

                  var verifier = generateCodeVerifier(128); 

                  console.log('authcode: '+authCode1);
                  console.log('codeVerif: '+codeVerif);
                  console.log('nonce1: '+nonce1);
                  console.log('verifier: '+verifier)
                      /* Register Command - mandatory */

                  AuthProvider.registerCommand('getAuthCode', (e) => {
                      e.resolve({
                          authCode: authCode1,  
                          redirectUri: 'http://localhost',  
                          nonce: nonce1,  
                          maxAge: 86400,      
                          codeVerifier: verifier  
                        });
                    

                  });

                  AuthProvider.subscribe('Auth.ready', (res) => {
                          //bAuthenticated = AuthProvider.data('Auth.authenticated');
                          console.log('AUTH READY');
                          console.log(res);
                  });

                  AuthProvider.subscribe('Auth.authenticated', (res) => {
                              console.log('Auth.authenticated');
                              console.log(res);
                  });
                    
                  AuthProvider.ready();

                }

      });
      
    })(); 

But I always got error 401, for tokenexchange.

Just wondering if you can help advise, if there's anything wrong ?

thanks
Fransiska

hi @Angelo_Cicchitto ,

I got this working now, thanks for all help.

Fransiska

1 Like

Excellent, thank you Fransiska!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.