Custom OAuthLink Component

Introduction

With Oracle Intelligent Bots (IB), each state within the Bot flow has the ability to invoke a component to perform actions that can range from basic interactions – taking user input and providing a textual response – to the more complex – some service-specific action like creating an order. IB provides a set of built-in components that support basic actions like setting variables, enabling user input and enabling OAuth. If the Bot calls for a specific action that’s outside of these functions, or need to add some additional UI based customizations, you’ll need to implement a custom component.

Main Article

In this article, the focus will be on creating a custom component based on the out-of-the-box (OOTB) System.OAuthAccountLink component. The OAuthAccountLink component allows the Bot to make requests to an OAuth Resource Server on the user’s behalf; in practice this means connecting to something like LinkedIn as if it were the user. This is done in a “two steps” manner. In step 1, the user follows a link (provided by the OAuthAccountLink component) to an OAuth Authorization Server to ask for permission. Once the user logs-in (or clicks Allow), thus granting permission, the OAuth Authorization Server generates an “Authorization Code”. The Authorization Code is then sent via the callback to the Bot.

In the second step, which in this example, must be coded by the developer, the Bot presents that Authorization Code to the OAuth Authorization Server, along with its client ID and secret, then exchanges it for an OAuth Access Token. In the acctlink.js there is a commented section to where this part of the code will need to be developed.

What is OAuth? Basically, OAuth is a delegation authorization framework to enable apps (web, Mobile or Bot) to obtain limited scoped access to resources via REST/APIs. OAuth allows this without giving away a user’s password. For a simple analogy, think of the example of getting into your hotel room with a key card. The key card (e.g. Access Token) enables you to access your room (resource). How the key card was first obtained was by authenticating (presenting yourself and ID) to the front desk staff (Authorization Server).

By default, the running component looks like this in the Bot tester:

OOTBOAuthlink2

The following is the code that produces the UI.

For more information on the System.OAuthAccountLink component, please refer to the documentation.

Items marked with < … > are place holders. For example, “<OAuth provider URL>”, which needs a valid URL to the OAuth provider.

   oauthAccountLink:
     component: "System.OAuthAccountLink"
     properties:
       prompt: "Please login"
       variable: "oauthcode"
       authorizeURL: "<OAuth provider URL>?response_type=code&client_id=XXXX&redirect_uri=https%3A%2F%2Fhost%2Fconnectors%2Fv1%2Fcallback"
     transitions:
       actions:
         pass: "oauthpass"
         fail: "oauthfail"

The properties for the OAuthAccountLink component are:

Property Description Required?
prompt A text string used by both the Title element and the (login) button Yes
authorizeURL The URL to the OAuth provider that also has the following OAuth paramters: response_type, client_id, scope and redirect_uri Yes
translate To override the boolean value of the autoTranslate context variable No
variable The variable that will be set by the authorization token Yes

Currently, the properties of the OAuthAccountLink only has a “prompt” property that is used for both the “title” element and the “login” button. For example, here is how the component looks in Facebook.

OOTBOAuthlink1

For my use case, I not only want the possibility to have the text different. But, I would also like to include an image:

CustomAuthlink2

Implementation

I will not be going into detail of how to create a custom component. Please review that documentation for this. But, rather focus on the code that is responsible for enabling the desired UI customization and for (like the OAuthAccountLink) retrieving the Access Token. The example will be implemented in JavaScript, which is deployed to Node.js. However, you can also deploy the component to other technologies, for example, in OMCe (Oracle Mobile Cloud Enterprise). To configure the Component Service for OMCe, please see here.

Bot Code

The following is an example of the dialog (YAML) code that will invoke the custom component:

component: "acctlink"
   properties:
     title: "Please log in"
     buttonPrompt: "Click here"
     cancelPrompt: "Cancel"
     image: "<image url>"
     authUrl: "<OAuth provider URL>?response_type=code&client_id=XXX&redirect_uri="
     callbackUrl: "https://<bot-host>/connectors/v1/callback?state="
     authorizationCode: ""
    transitions: {}

 

As you can see in the example code above, the acctlink custom component contains custom properties that will be used to provide the customization for the UI (image and text for 2 buttons: buttonPrompt, cancelPrompt) and for the two URLs: one for OAuth provider (authUrl = OAuthAccountLink authorizeURL) and another (callbackUrl) for the callback to the Bot.

The OAuthAccountLink already includes the callback URL internally.

Custom Component Code

To enable the retrieval of the properties from the Bot dialog code, the properties should be mapped in the meta-data section of the custom component:

metadata: () => ({
        "name": "acctlink",
        "properties": {
            "authorizationCode": {
                "type": "string",
                "required": true
            },
            "title": {
                "type": "string",
                "required": true
            },
            "buttonPrompt": {
                "type": "string",
                "required": true
            },
            "cancelPrompt": {
                "type": "string",
                "required": true
            },
            "image": {
                "type": "string",
                "required": true
            },
            "authUrl": {
                "type": "string",
                "required": true
            },
            "callbackUrl": {
                "type": "string",
                "required": true
            }
        },
        "supportedActions": []
    }),

The following code references both the Bot SDK and the Message Model utility class for building of the UI. For more information about the SDK, please refer to the documentation.

The next step is to provide the logic to retrieve the Access Token. The following is the pseudo-code to perform this task:

The generation of the callbackToken in the working example uses the uuid Node.js module. For me information about uuid, see here.

invoke: (conversation, done) => {
    let callbackToken = <retrieve the callbackToken from the conversation.request()>;
    if (callbackToken == null){
        const callbackToken = "<generate a UUID>";
        const callbackURL =  "<callbackUrl>" + callbackToken;
        const callbackURLEncoded = "<encode the callbackURL>";
        const authURL = "<authUrl>" + ?client_id=<client_id_here>&redirect_uri=" + callbackURLEncoded;
        // TODO: build a card object with a card action (e.g. link) set to authUrl and then send back to Bot to display UI
        conversation.reply(card);
        conversation.setCallbackToken(callbackToken);    
    } else {
        conversation.setVariable("authorizationCode", "<returned access code>");
        conversation.transition();
        conversation.setCallbackToken(null);
    }
    done();

}

Simply, the logic checks for the existence of the generated callbackToken. If not present (e.g. first time invocation of component), create the callBackToken by using a random generator, assemble the call back (to the Bot) URL with the generated token appended, encode that URL and then append the encoded URL to the (OAuth provider) URL. Next, assemble the card for the UI with the (Action) button set to the (OAuth) URL and finally send the UI based response back to the Bot for display.

An important sequence is the invocation of the conversation.setCallbackToken(), which is passed in the generated callbackToken. This assures that the call back returns to the same (Bot) request.

Upon the call back from the OAuth provider, the callbackToken will have been set, so the code just sets the authorizationCode variable.  This is the value that can be used for subsequent REST API invocations.

The code to produce the example UI exemplified by the screen shot above uses the MessageModel SDK to construct the card object:

const MessageModel = conversation.MessageModel();
let cardActions = [];
const oauthButton = MessageModel.urlActionObject(buttonPrompt, null, authURL);
const cancelButton = MessageModel.postbackActionObject(cancelPrompt, null, 'cancel');
cardActions.push(oauthButton);
cardActions.push(cancelButton);
const card = MessageModel.cardObject(title, null, image, null, cardActions);
const cardMessage = MessageModel.cardConversationMessage(null, [card], null);

conversation.reply(cardMessage);

Example Code and Testing

The example code, which can be downloaded here, provides everything you need to examine, run and test the OAuthLink custom component. The component is deployed within the Custom Component Service Express Starter App that will run on your local environment. The Component Service implementation in the Express Starter App is based on Express.js. The supporting files included are:

package.json This is the standard package.js file used by Node.js
index.js The main Javascript file. It implements the Bot Component REST API by delegating most of the functions to the shell.js object.
registry.js Lists the custom component that are managed by the Component Service.
shell.js A utility object that is responsible for both finding and invoking the custom components.
component.js The Component Service implementation.
sdk.js Bot SDK v 1.1.
MessageModel.js The utility class for implementing UI in Bot.
CustomOAuthLinkingComponent.zip The sample Bot to test the custom component.
README.md Instructions on installation of the sample

You will need to have Node.js installed to execute the app and possibly a utility like ngrok to access the starter app from the Bot.

You can get information about configuring the Component Service for Oracle Mobile Cloud Enterprise (OMCe) here. To download the OMCe custom component SDK see here. Please note that you will need to include the supporting custom component code (acctlink.js), install the uuid module and register the component in the registry.js, before importing the SDK into OMCe.

Summary

Like the built-in components, the custom components are re-usable units of work that you define within each state of your dialog flow. But unlike the built-in components, custom components perform actions that are specific to your bot. They can execute functions that the system components can’t. In addition, as I have shown in this blog, you can also customize a System component to provide additional functionality or alter the UI.

Add Your Comment