To create your custom authentication connector, we recommend that you first create a sample custom authentication connector and edit the generated files. It’s easier to get all the files and directory structure your connector needs by just using an existing example.
To create your custom authentication connector, do the following steps.
Enter the following command to create the connector:
taco create my-custom-auth-connector --boilerplate custom-auth
This creates a directory with the earthquake data boilerplate code, which is included with the toolkit.
my-custom-auth-connector
directory.
cd my-custom-auth-connector
Build the connector by entering the following command:
taco build
This command clears any earlier or existing build caches. Then the command installs the dependencies and builds both the front-end code and the back-end code (handlers). Finally, the command copies the connector.json
file (the configuration file) to your directory.
In your new custom authentication connector directory, find and open the connector.json
file.
{
"name": "my-custom-auth-connector",
"version": "1.0.0",
"tableau-version": {
"min": "2022.3",
},
"vendor": {
"name": "vendor-name",
"support-link": "https://vendor-name.com",
"email": "support@vendor-name.com"
},
"permission": {
"api": {
"https://*.usgs.gov/": [
"GET",
"POST",
"HEAD"
],
"https://*.your_token_url/": [
"GET",
"POST",
"HEAD"
]
}
},
"auth": {
"type": "custom"
},
"window": {
"height": 800,
"width": 600
}
}
Make the following changes:
Change the general properties.
Name | Value |
---|---|
name | Your connector’s name |
version | Your connector’s version |
min | The earliest Tableau version your connector supports |
Change the company properties.
Name | Value |
---|---|
vendor.name | Your company name |
vendor.support-link | Your company’s URL |
vendor.email | Your company’s email |
Change the permissions.
Name | Value |
---|---|
permission.api | The URI for the API that the connector is allowed to access, along with the methods (POST, GET, PUT, PATCH, DELETE) that the connector is allowed to use. |
.
Name | Value |
---|---|
auth.type | Set to custom-auth |
For more information about authentication, see the Authentication section in the Considerations for Building Your Connector topic.
Change the HTML pane size.
Name | Value |
---|---|
window.height | The height of the connector HTML pane |
window.width | The width of the connector HTML pane |
When you open a web data connector in Tableau, the connector displays an HTML page that links to your JavaScript code and to your connector’s handlers. Optionally, this page can also display a user interface for your users to select the data that they want to download.
To create a user interface for your connector, open the /app/index.html
file.
<!DOCTYPE html>
<html>
<head>
<title>Custom Auth Sample Connector</title>
<meta http-equiv="Cache-Control" content="no-store" />
<link rel="shortcut icon" href="#" />
<link href="index.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="index.js" type="module"></script>
</head>
<body>
<p id="error" style="display: block; margin-top: 2em; height: 5px; text-align: center; color: red;"></p>
<div class="box m-auto ">
<div class="card">
<div class="card-header">
Custom Auth Sample Connector
</div>
<div class="card-body">
<label for="accessToken" class="form-label">Access Token</label>
<textarea type="text" id="accessToken" class="form-control mb-3" placeholder="Access Token"></textarea>
<label for="refreshToken" class="form-label">Refresh Token</label>
<textarea type="text" id="refreshToken" class="form-control mb-4" placeholder="Refresh Token"></textarea>
<div class=" text-center">
<button type="button" class="btn btn-success" id="submitButton" disabled> Please wait while settings load...</button>
</div>
</div>
</div>
</div>
</body>
</html>
Some notes about what the code is doing:
meta
tag prevents your browser from caching the page.index.css
and bootstrap.min.css
files are used to simplify styling and formatting.index.js
file is the code for your connector.input type="text"
is the form field for the username.<input type="password"
is the form field for the password.Now that you’ve created a user interface, it’s time to edit the JavaScript code for the connector’s button. Open the /app/index.js
file.
import Connector from '@tableau/taco-toolkit'
const connector = new Connector(onInitialized)
function onInitialized() {
const elem = document.getElementById('submitButton')
elem.innerText = 'Get Data'
elem.removeAttribute('disabled')
setCredential()
document.getElementById('accessToken').focus()
}
function setCredential() {
if (!connector.secrets) return
const { accessToken, refreshToken } = connector.secrets
document.getElementById('accessToken').value = accessToken
document.getElementById('refreshToken').value = refreshToken
}
function submit() {
const accessToken = document.getElementById('accessToken').value
const refreshToken = document.getElementById('refreshToken').value
if (!accessToken) {
return
}
connector.secrets = {
expires_in: Date.now() + 60 * 60 * 1000, //expires in an hour
access_token: accessToken,
refresh_token: refreshToken,
}
//TODO: change the url to your api url
connector.handlerInputs = [
{
fetcher: 'CustomAuthFetcher',
parser: 'CustomAuthParser',
data: {
url: 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_week.geojson',
},
},
]
connector.submit()
}
window.addEventListener('load', function () {
document.getElementById('submitButton').addEventListener('click', submit)
})
Some notes about the code:
If your data is complex and needs preprocessing, use the TACO Toolkit library to prepare your data. The following is the default code that the fetcher uses to get the data:
import { Fetcher, FetchUtils, getAuthHeader } from '@tableau/taco-toolkit/handlers'
const getToken = async (refresh_token) => {
const tokenURL = `[Your Token Url]` //TODO: add your token Url
const headers = getAuthHeader(refresh_token)
const data = await FetchUtils.fetchJson(tokenURL, {
method: 'POST',
headers,
})
return data.access_token
}
export default class CustomAuthFetcher extends Fetcher {
async *fetch({ handlerInput, secrets }) {
const { access_token, refresh_token, expires_in } = secrets
const isTokenExpired = Date.now() > (expires_in || 0)
const token = isTokenExpired ? getToken(refresh_token) : access_token
const headers = getAuthHeader(token)
yield await FetchUtils.fetchJson(handlerInput.data.url, { headers })
}
}
headers
contain the custom authorization token.Now you must define how you want to map the data to one or more or tables. This mapping of data is done in the schema.
To decide how to map your data, look at your data source. When you’re done looking at the summary of the JSON data source, make the necessary edits to structure the returned data.
import { DataType, Parser } from '@tableau/taco-toolkit/handlers'
export default class CustomAuthParser extends Parser {
//TODO: Update the columns to match your api result
parse(fetcherResult, { dataContainer }) {
const tableName = 'CustomAuthTable'
const containerBuilder = Parser.createContainerBuilder(dataContainer)
const { isNew, tableBuilder } = containerBuilder.getTable(tableName)
if (isNew) {
tableBuilder.addColumnHeaders([
{
id: 'id',
dataType: DataType.String,
},
{
id: 'title',
alias: 'title',
dataType: DataType.String,
},
])
}
const rows = fetcherResult.features.map((row) => ({
id: row.id,
title: row.properties.title,
}))
tableBuilder.addRows(rows)
return containerBuilder.getDataContainer()
}
}
Enter these commands to build, pack, and run your new connector:
taco build
taco pack
taco run Desktop