PingOne DaVinci

Launching a flow with the widget

Launch a prepared flow with a widget.

This method is effective when you want to launch the flow within the current page instead of redirecting the user.

To switch between using a flow for a PingOne redirect integration and an integration using the DaVinci widget, see Switching between PingOne and DaVinci widget integrations.

Configuring the Flow

Prepare a flow to be launched with the widget.

About this task

  • This procedure only covers the steps and nodes required to prepare a flow for widget invocation. It assumes that you have already created a flow for the purpose you have in mind. See the Getting started with DaVinci and DaVinci Best Practices documentation for more information about building flows.

  • Flows launched with the widget cannot receive the PingOne session cookie.

Steps

  1. Click the Flows tab.

  2. Find the flow and click ... → Edit

  3. Add a nonce to the input schema.

    1. Click Flow Options ( ) → Input Schema.

    2. Click Add.

    3. In the Parameter Name field, enter nonce.

    4. In the Data Type list, select String.

    5. Select Required.

    6. Click Save.

  4. At the end of the success path, add a PingOne Authentication node or an HTTP node to send a success response.

  5. At the end of any failure paths, add a PingOne Authentication node or an HTTP node to send an error response.

  6. Click Save.

  7. Click Deploy.

Creating an Application

Create an application in DaVinci to enable your flow.

About this task

If you want to use an existing application to launch the flow, you can start at step 5.

Steps

  1. Click the Applications tab.

  2. Click Add Application.

    The Add Application modal opens.

  3. In the Name field, enter a name for the application.

  4. Click Create.

  5. Find the application and click Edit.

  6. On the General tab, note the following parameters:

    1. Note the Company ID.

  7. Create a flow policy:

    1. Click the Flow Policy tab.

    2. Click Add Flow Policy.

    3. In the Name field, enter a name for the flow policy.

    4. In the flow list, select your flow.

    5. In the version list, select Latest Version.

    6. Click Create Flow Policy.

      The Edit Your Weight Distribution modal opens.

      This example only uses one flow, but if your flow policy included multiple flows or flow versions, you could use this modal to split traffic between them.

    7. Click Save Flow Policy.

    8. Note the Policy ID of your flow policy.

Integration example

This example is a simple hello-world application that shows you how to specify the DaVinci API domain, your company ID, flow policy ID, and DaVinci access token, which then integrates your single-page app with the DaVinci application and associated flow policy.

The following example won’t work unless you add your region-specific information. Replace any instances of <region> with your regional top-level domain:

  • Use .com for North America.

  • Use .ca for Canada.

  • Use .eu for EMEA.

  • Use .asia for APAC.

  • Use .com.au for Australia.

<!DOCTYPE html>
<html lang="en">
  <meta charset="UTF-8" />

  <head>
    <title>Simple HTML/JS widget sample</title>
  </head>

  <body>
    <h3>Simple HTML/JS widget sample</h3>
    <br />
    <p>Widget will be displayed below</p>
    <br />
    <div id="widget" class="skWidget">Widget should appear here</div>

    <script
      type="text/javascript"
      src="https://assets.pingone.<region>/davinci/latest/davinci.js"
    ></script>
    <script>
      //*** Populate the parameters below from your DaVinci environment ***/
      const companyId = "<companyId>";
      const skApiKey = "<apiKey>";

      //*** Build the get SK Token URL. ***/
      const skGetTokenUrl =
        "https://orchestrate-api.pingone.<region>/v1/company/<companyId>/sdktoken";

      //*** Add the API Key from your DaVinci application. ***/
      var headers = new Headers();
      headers.append("X-SK-API-KEY", skApiKey);

      var requestOptions = {
        method: "GET",
        headers: headers,
        redirect: "follow",
      };

      //*** Retrieve SK Token ***/
      fetch(skGetTokenUrl, requestOptions)
        .then((response) => response.json())
        .then((responseData) => {
          var props = {
            config: {
              method: "runFlow",
              apiRoot: "https://auth.pingone.<region>/",
              accessToken: responseData.access_token,
              companyId: companyId,
              policyId: "<policyId>",
            },
            useModal: false,
            successCallback,
            errorCallback,
            onCloseModal,
          };
          /*** Invoke the Widget ****/
          console.log(props);
          davinci.skRenderScreen(
            document.getElementsByClassName("skWidget")[0],
            props
          );
        })
        .catch((error) => console.log("error", error));

      function successCallback(response) {
        console.log(response);
      }

      function errorCallback(error) {
        console.log(error);
      }

      function onCloseModal() {
        console.log("onCloseModal");
      }
    </script>
  </body>
</html>

Getting the SDK token

When implementing a DaVinci application integration using the widget method, be aware that the POST <authPath>/<companyID>/davinci/policy/<davinciFlowPolicyID>/start request that invokes the flow takes an SDK token to authenticate. However, the call to get a DaVinci SDK token, GET <orchestratePath>/company/<companyID>/sdktoken, requires the application’s API key to authenticate.

The /sdktoken call must be executed on the server side, not in client-side code, to protect the application’s API key from exposure on a public web page.

The following sample shows a server-side code snippet from a server.js file used to generate the DaVinci SDK token without exposing the application’s API key.

The sample won’t work unless you add your region-specific information. Replace any instances of <region> with your regional top-level domain:

  • Use .com for North America.

  • Use .ca for Canada.

  • Use .eu for EMEA.

  • Use .asia for APAC.

/************************
* DaVinci components
************************/

// Get a Widget sdkToken
function getDVToken(cb) {
  const url = 'https://orchestrate-api.pingone.<region>/v1/company/${companyId}/sdktoken';
  fetch(url, {
    headers: {
      "X-SK-API-KEY":  <yourDavinciAppApiKey>
    },
    method: "GET"
  })
  .then(res => res.json())
  .then(data => cb(data))
  .catch(err => console.log("Error: ", err));
}

Using the widget with a return URL

When using the widget with social providers, PingID, or other services requiring you to supply a return URL, add coding similar to this.

Retrieve the value for a continueToken.

/**
 * Event listener for window.load()
 * Listening for a query parameter of `continueToken`
 */
window.addEventListener('load', (event) => {
  var urlParams = new URLSearchParams(window.location.search);
  if (urlParams.get('continueToken')) {
    // flush parameter from window url
    window.history.pushState({}, document.title, window.location.pathname);
    continueWidget('policyId', 'authnflow', urlParams.get('continueToken'))
  }
});

Invoke the widget and continue the flow using the continueToken.

The following example won’t work unless you add your region-specific information. Replace any instances of <region> with your regional top-level domain:

  • Use .com for North America.

  • Use .ca for Canada.

  • Use .eu for EMEA.

  • Use .asia for APAC.

/**
 * Recreates an instance of the Widget placed on the page,
 * and uses the provided 'continueToken' value instead of fetching a new one from DaVinci
 * @param {string} policyId - The flow policy ID for the widget to run
 * @param {string} divId - Location on the page to place the Widget
 * @param {string} continueToken - Value of the 'continueToken' query parameter
 */
function continueWidget(policyId, divId, continueToken){
  /**
   * Creates an instance of the Widget with the following:
   * @param {object} props - Properties for the Widget execution
   * @param {object} props.config - Object containing the Widget configuration
   * @param {string} props.config.method - Widget run method { "runFlow" | "continueFlow" }
   * @param {string} props.config.apiRoot - URL of the DaVinci instance for this flow
   * @param {string} props.config.accessToken - @param {string} continueToken
   * @param {string} props.config.companyId - ID of the PingOne environment that contains the flow
   * @param {string} props.config.policyId - Flow policy ID for the Widget to run
   * @param {boolean} props.useModal - Present Widget as a modal, instead of embedded
   * @param {requestCallback} props.successCallback - The callback that handles the Success response
   * @param {requestCallback} props.errorCallback - The callback that handles the Error response
   * @param {requestCallback} props.onCloseModal - The callback that handles the modal close response ('useModal' == true)
   */
  var props= {
    config: {
      method: 'continueFlow',
      apiRoot: 'https://auth.pingone.<region>/',
      accessToken: continueToken,
      companyId:  <companyID>,
      policyId: policyId`
    },
    useModal: false,
    successCallback, errorCallback, onCloseModal
    }
    /*** Invoke DaVinci Widget ****/
    davinci.skRenderScreen(document.getElementById(divId),props)
  }

Limiting the cookies passed by the widget

By default, the widget passes to DaVinci all cookies that could be presented to the origin. There can be a large number of cookies, only some of which are likely to be used for your DaVinci flows. In some cases, this can cause a 431 Error: Request Header Fields Too Large. To avoid this possibility, you can set the originCookies property.

The originCookies property is optional and accepts a string array of cookie names. Only the cookies specified will be passed by the widget to DaVinci. Set this as you would any of the DaVinci properties.

The following example won’t work unless you add your region-specific information. Replace any instances of <region> with your regional top-level domain:

  • Use .com for North America.

  • Use .ca for Canada.

  • Use .eu for EMEA.

  • Use .asia for APAC.

  • Use .com.au for Australia.

var props= {
   config: {
     apiRoot: 'https://auth.pingone.<region>/',
     companyId:  <companyID>,
     policyId:  <policyId>,
     originCookies: ["cookie-1", "cookie-2"]
   }
}

To disable passing cookies from the widget, set originCookies to an empty array.