Callbacks

Describes the general usage of Callbacks in the Auth Service.

Callbacks are an optional recommended feature of the Privakey CX Auth Service. They are used to push updates on challenge requests to a URI of your choice to eliminate the need for polling. When a request is processed by an end user, the entirety of the processed request is sent to the URI of the Callback via POST body as JSON.

Callback URIs are configured in the Privakey CX Admin Portal. For more information on whitelisting a Callback, see the section on configuring Callbacks. For more information on adding a challenge request, see the API documentation.

By parsing the data of the request JSON sent to the Callback URI, it is possible to determine how the user responded, and use this information to provide a dynamic experience, invoke custom business logic, or any other action that could be triggered by a user's response to the challenge.

A Callback URI is sent to the Auth Service as part of the data used to create a challenge request. In order for the addRequest call to be accepted, the Callback must be whitelisted for the Request Origin creating the challenge. A Request Origin can have multiple Callbacks whitelisted. If a Callback is sent to the addRequest endpoint in the Auth Service that is not white listed, the request will be rejected with a 400 error.

A challenge request can be added without sending a Callback, in which case you can still determine what the user's response was by polling the getRequest endpoint, although this is NOT recommended.

Example: A secure web login

The most immediate example highlighting the benefits of Callbacks is performing a secure login without, or in addition to, a traditional password entry on a web page. Below is a basic example of how this might work.

πŸ“˜

Example Code

Although the following example is written in javascript, it should be considered pseudo code.

  • The flow begins with the user initiating a login on your site.
  • The site, a registered Request Origin, calls the addRequest endpoint of the Auth Service, adding a challenge request for the login, and storing the request guid that is returned along with the user record.
axios.request({
    url: privakeyUrl + 'request/add',
    method: 'post',
    headers: {
        'Authorization': 'Basic ' + privakeyBasicAuth,
        'Content-Type': 'application/json'
    },
    data: {
        'accountId': accountId,
        'callback': thisServerUrl + '/auth/processRequest', // Note the callback is sent along
        'content': content,
        'duration': duration,
        'additionalInfo': '{"viewType": "html", "format": "standard"}',
        'showNotification': true
    }
});
  • The user in the app will then receive the request and respond appropriately.
  • When the challenge request is completed, the result is sent to the Auth Service which then forwards the challenge's response to the Callback endpoint via POST.
  • Example POST content:
{
  "code":"WOU",
  "created":"2019-06-20T15:34:30.000Z",
  "lastModified":"2019-06-20T15:34:55.000Z",
  "expiration":"2019-06-20T15:44:30.000Z",
  "originIP":"::ffff:3.83.44.226",
  "requestTypeId":1,
  "requestStatusId":2,
  "content":"Please confirm you are trying to log in.",
  "responseContent":"Login confirmed",
  "buttons":[
    {"title":"Approve","strongAuth":true},
    {"title":"Reject","strongAuth":false}
  ],
  "buttonSelected":1,
  "privakeyId":"620f4306-2ec7-4e22-b2ef-9852cad8878c",
  "requestOriginId":1,
  "additionalInfo":"{'viewType': 'html', 'format': 'standard'}",
  "showCode":0,"callback":"https://privakey-mern.herokuapp.com/auth/processRequest",
  "notificationBody":"Authentication Request",
  "notificationTitle":"Authentication Request",
  "guid":"61f98330-93c7-480c-b26c-9a1234a2e539",
  "showNotification":1,
  "appSpaceId":1
}
  • At the Callback location, the response data is used to determine if the login will be completed or not (ie which option, or "button" they selected).
// route auth/processRequest
// Lets the user know their request has updated. This is called by the Privakey CX Auth Server.
    router.post('/processRequest', (req, res) => {
      // Get the request information
      let challengeResponse = req.body;
      // Double check this isn't some random POST
      if (req.body.guid) {
        // Find the user in our database by the request guid, which we previously stored during
        // addRequest call earlier
      	User.findOne({ challengeGuid: req.body.Guid }).then(user => {
          if (user != null) {
            // If the user completed the challenge by selecting the first button, "Approve Login"
            // then complete the login
            if (req.body.buttonSelected == 0) {              
              completeLogin(user);
            } else {
              displayMessage('The login process has been canceled.');
            }
          } 
        });
      }
    }