Community Spring Cleaning week is here! Join your fellow Maveryx in digging through your old posts and marking comments on them as solved. Learn more here!

Engine Works

Under the hood of Alteryx: tips, tricks and how-tos.
Ozzie
Alteryx
Alteryx

As mentioned in our Overview of Alteryx Developer Platform blog post, The HTML GUI SDK lets users create custom GUIs using HTML5. This allows for greater UI customization than what standard Macro interfaces provide as well as more dynamic interaction with web-services. This makes building a connector with the HTML GUI SDK more attractive especially when it comes to authentication.

Authentication is almost always the very first step toward interacting with a web-service, making it the most crucial to get right. Even though it is possible to get through authentication using just the Download Tool within a macro, you may run into some hurdles depending on the web-service. Currently the Download Tool does not support HTTPS or redirect URIs, so you may have to get creative and maybe use a run command tool running a cURL script for certain web-services. For more information on creating your own connector in Alteryx using macros as well as the authentication process in macros and workflows, checkout the Guide to Creating Your Own Connector Series.

In this blog post, we will go over an example of how the authentication process can interact with the HTML GUI SDK. Specifically, we will look at an example from the newest version of the Google Analytics Connector. The new connector can be downloaded on the gallery but the code that we will be reviewing can only be found in our GitHub repository. The reason these two entities are different are because the files contained in the YXI package found in the gallery, which automatically get installed into C:\Users\{user}\AppData\Roaming\Alteryx\Tools, do not include developer dependencies or other files unnecessary for the tool to function such as node.js packages or component files. The YXI will only include a bundled file (bundle.js) generated via webpack that the HTML uses. In this post, we will be going over code located in the utils.js file located under .\Google Analytics\App\src\utils.

 

 

repodir.png

 

 

 

Before we jump into the code here is a short list of tools we used in this section of code:

  • jquery - For ajax calls to validate our token and the API call for the offline authentication method.
  • HTML GUI SDK - For extracting and setting values of widgets and DataItems. Note, this tool uses version 1 of the SDK. The only method we use from the SDK in this example is Alteryx.Gui.manager.GetDataItem(). In version 2 this was changed to Alteryx.Gui.Manager.getDataItem().


The connector has two client-side authentication methods: Online and Offline.

The Online method allows users to sign-in with their Google credentials however, they will be logged out after 60 minutes. This method requires using OAuth 2.0. To implement OAuth 2.0 authorization for Google APIs into your Alteryx plugin, follow Google's guide OAuth 2.0 for Client-side Web Applications.

The Offline method allows users to stay logged in permanently thus allowing workflows to be scheduled and ran indefinitely. This method requires a Client ID, Client Secret, and Refresh Token. Read our help documentation to obtain the credentials.

 

 

 

image.png

 

Online Method

 Again the following code is from the utils.js module. We'll cover three functions:

 

  1. login
  2. gup
  3. validateToken

 

Online Method - login

 

The login function has a few constants needed for the request URL stored in the variable _url.

 

const OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?'
const SCOPE = 'https://www.googleapis.com/auth/analytics.readonly'
const CLIENTID = '552512737410-g6admen5hqg6q268dmt3d9bminlri7en.apps.googleusercontent.com'
const REDIRECT = 'https://developers.google.com/oauthplayground'
const TYPE = 'token'
const _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE

Then the variable win is created using _url as a parameter. Don't worry about the line right below win. The data item is being used to store the error status, which we initialize with a blank value during the login process.

win will open a new window to Google's OAuth URL where the user can login with their credentials.

 

const win = window.open(_url, 'windowname1', 'width=800, height=600')
Alteryx.Gui.manager.GetDataItem('errorStatus').setValue('')

While the window is open, a poll timer function is running every half second checking if the URL origin has changed to https://developers.google.com. The URL origin will change if the user successfully logins. When that happens, steps 2 and 3 occur. The access token is parsed from the URL using the gup function and stored in the 'access_token' DataItem so that it can be used for the downstream API call in the macro. The access token is then validated using the validateToken function. Both are discussed in the next sections.

If the access token validates successfully the window is closed and the plugin's configuration page changes to the profile selection.

 

const pollTimer = window.setInterval(() => {
try {
if (win.document.location.origin === 'https://developers.google.com') {
const url = win.document.URL
const accessToken = gup(url, 'access_token')
Alteryx.Gui.manager.GetDataItem('accessToken').setValue(accessToken)
validateToken(accessToken)
win.close()
setPage('#profileSelectors')
}
} catch (e) {
// console.log("catch");
}
}, 500)

 

Online Method - gup

 

This is a simple function that takes the URL and the query parameter as arguments to identify the value needed. For example, if the function is invoked as gup('http://www.alteryx.com/index.html?foo=bar&?data=123', 'foo') it will return 'bar'.

 

const gup = (url, name) => {
name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]')
const regexS = '[\\#&]' + name + '=([^&#]*)'
const regex = new RegExp(regexS)
const results = regex.exec(url)
if (results == null) {
return ''
} else {
return results[1]
}
}

 

Online Method - validateToken

 

After the access token is parsed from the URL, it is validated with the JQuery ajax method. The settings object is the only argument for $.ajax needed because it contains the validation URL and the access token.

If $.ajax is successful, then the Google Analytics will continue to run normally otherwise the tool will error out.

 

const validateToken = (token) => {
const VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='

// API call settings
const settings = {
'async': true,
'crossDomain': true,
'url': VALIDURL + token,
'method': 'GET',
'dataType': 'jsonp'
}
return $.ajax(settings)
.done(ajaxSuccess)
.fail(connectionError)
}

 

Offline Method

 

The Offline method is a little more straight forward. As stated above, the user will can get their developer credentials through the help documentation.

Here we'll cover two main functions:

 

  1. getAccessTokenAjaxCall
  2. checkToken

 

Offline Method - getAccessTokenAjaxCall

 

Since the credentials are stored in Alteryx widgets, we can obtain them using the GetDataItem method as shown below. Similar to the validateToken function above, store the values of the credentials in the settings object and use it as an argument for $.ajax.

 

const getAccessTokenAjaxCall = () => {
// Add vars for each of the user text box inputs
const clientID = Alteryx.Gui.manager.GetDataItem('client_id').value
const clientSecret = Alteryx.Gui.manager.GetDataItem('client_secret').value
const refreshToken = Alteryx.Gui.manager.GetDataItem('refresh_token').value

// API call settings
const settings = {
'async': true,
'crossDomain': true,
'url': 'https://accounts.google.com/o/oauth2/token',
'method': 'POST',
'dataType': 'json',
'headers': {
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded'
},
'data': {
'client_id': clientID,
'client_secret': clientSecret,
'refresh_token': refreshToken,
'Host': 'accounts.google.com',
'grant_type': 'refresh_token'
}
}

return $.ajax(settings)
.done(checkToken)
.fail(connectionError)
}

 

Offline Method - checkToken

 

If the AJAX request was successful, checkToken will proceed to run. Here we obtain the access token and set the value of the 'accessToken' DataItem to the access token we just received. Once set, we remove any error messaging and display the proper HTML page to the user. 

 

const checkToken = (data) => {
if (typeof data.errors === 'undefined') {
// Set access token
const accessToken = data.access_token
Alteryx.Gui.manager.GetDataItem('accessToken').setValue(accessToken)
}
// Remove any error messaging
store.errorStatus = ''
// Change page to current page or profileSelectors
console.log('store page: ' + store.page)
switch (store.page) {
case '':
displayFieldset('#accessMethod')
break
case '#offlineCreds':
store.page = '#profileSelectors'
displayFieldset('#profileSelectors')
break
default:
displayFieldset(store.page)
}
}

 

Store Access Token in Data Items

 

Now if you noticed in both the Online and Offline methods, the access token is stored in the accessToken DataItem. Once this value is stored in this DataItem, it will actually be passed down into a textbox interface tool inside Google_Analytics.yxmc macro, which is the engine of the connector. This DataItem can be associated with the TextBox interface matching annotation name. When this happens the DataItem will now be present in this tools configuration XML. When the tool runs, the access token will be available in stream and will eventually get passed on to a Download tool as a header in the subsequent calls. This must done for any key-value pair if it needs to be used in the macro engine.

 

GAaccesstoken.PNG

 

And that's it! This is how authentication works for the Google Analytics connector. Other tools that use this method include Adobe Analytics and Google Sheets.

Please ask any questions and share any comments or tools you've created! We love seeing what fellow Alteryx developers build.

Ozzie Dembowski
Software Engineer

Ozzie is a Software Engineer that began his career at Alteryx as a Customer Support Engineer in January of 2016. After learning the in's and out's of Alteryx and having a love for building stuff, he couldn't help himself but tinker more with the product and create custom tools and macros every chance he could. Ozzie now spends his days building tools that keep pushing the boundaries of what Alteryx can provide. When he is not coding, he is probably traveling or critiquing beer.

Ozzie is a Software Engineer that began his career at Alteryx as a Customer Support Engineer in January of 2016. After learning the in's and out's of Alteryx and having a love for building stuff, he couldn't help himself but tinker more with the product and create custom tools and macros every chance he could. Ozzie now spends his days building tools that keep pushing the boundaries of what Alteryx can provide. When he is not coding, he is probably traveling or critiquing beer.

Comments