Auth for HTTP APIs
To use an HTTP API such as a trigger or getting device info, you'll need to get a valid authentication token. This is so an HTTP request (i.e., trigger) can come from only the parties you authorize.
Utilities Available
Included in the Relay SDK are utility functions that makes it easy to create and send an HTTP trigger or send an HTTP device info request, which are the two common items that require HTTP authentication. These utilities hide the network operations and authentication mechanics, making it much easier for you. The content below describes how to do it manually, but you'll probably want to use these utility methods instead and can stop reading here. See the
triggerWorkflow
andfetchDevice
methods in the "Special Utilities" section on the Utilities page. If you are doing something different, such as fetching analytics or configuring NFC tags, then you'll need to keep on reading below.
As a quick background, Relay uses two kinds of tokens: refresh_token
and access_token
. Ultimately, you'll want to use an access_token
when accessing an HTTP API, it goes in the Authorization header. An access_token
has a limited lifetime (single-digit hours) before it expires. When an access_token
does expire, you need to generate a fresh new one from a refresh_token
. The refresh_token
has an unlimited lifetime, and is used only to create an access_token
. Both should be treated with care to prevent unauthorized parties from seeing them, but in particular the refresh_token
, because it has an unlimited lifetime.
To start, let's assume you've already registered an HTTP workflow:
$ relay workflow create http --trigger=POST --name my_http_wf \
--uri wss://mywfserver.mydomain.com/hellopath --install 99000756034567
Relay CLI Versions
The
token:generate
command is currently available only in the beta branch of@relaypro/cli
. You may need to update it by runningnpm install -g @relaypro/cli@beta
.
To start, use the CLI to generate a refresh token:
$ relay token generate
Opening browser to login
relay: Waiting for login... done
=== SDK TOKEN
The following token can be used in the configured environment
api: all-main-pro-ibot.relaysvr.com
env: pro
token: 8bf427df18d88ce4e16ea812b9dXXXX
When prompted to login via the web, make sure you check the 'Remember me' button. You may need to sign out before logging in again.

Great, we've got a refresh token! This is a permanent refresh token and can be used to generate access_token
s indefinitely, as each access_token
has a limited lifetime. Don't share the refresh token with anyone!! Next, let's grab the environment ID & auth server:
$ relay env
=== ENVIRONMENT
api: all-main-pro-ibot.relaysvr.com
auth: auth.relaygo.com
auth_cli_id: 4EgeETYm
auth_sdk_id: RJZKRhh9
env: pro
=== USAGE
Define API and Auth Hosts using shell environment variables:
# Auth
RELAY_ENV=pro # default
RELAY_ENV=qa
# API
RELAY_HOST=all-main-pro-ibot.relaysvr.com # default
RELAY_HOST=all-main-qa-ibot.relaysvr.com
Now you can use that refresh token to generate an access_token from the auth server. Access tokens are valid for 2 hours. You can generate an access token either from the command line or using your favorite framework, for Node we like axios. For the path part of the auth server URL, use /oauth2/token
.
curl -vv -d "grant_type=refresh_token&client_id=RJZKRhh9&refresh_token=8bf427df18d88ce4e16ea812b9dXXXX" \
-H "Content-Type: application/x-www-form-urlencoded" \
-X POST https://auth.relaygo.com/oauth2/token
async function refresh_auth() {
try {
const response = await axios.post(auth_endpoint, new URLSearchParams({
'grant_type': 'refresh_token',
'client_id': 'rGGK996c',
'refresh_token': process.env.REFRESH_TOKEN
}),
{
headers : {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
return response.data.access_token
} catch (err) {
console.error(err)
}
}
This access_token
is what you will use in the auth header for your HTTP trigger request.
If using curl above, in the returned JSON document, use the access_token
value, not the id_token
value.
When to Create Access Tokens
When getting an
access_token
for the Authorization header of your http trigger, the best practice is to avoid creating a new access token for each trigger invocation. Instead, cache the access token from previous use, and create a new access token only when its use returns a 401 code.
Now you have almost everything you need. One missing piece is the id of the workflow, which you can obtain via the CLI:
$ relay workflow list
=== Installed Workflows
ID Name Type
ββββββββββββββββββββββββββββββββββββββ ββββββββββββ ββββββββββββββββ
wf_http_Y4xdLSLW8gJIpGaCjqOSp3 my_http_wf http:POST
The last missing piece is the subscriber id, which you can also obtain via the CLI:
$ relay whoami
=== You are
Name: Alice Rodriguez
Email: [email protected]
Default Subscriber: ee4547e0-aaef-4956-b853-ad0123456789
Auth User ID: 98071da3-572b-4552-be88-8907a9ad03ef
Relay User ID: VIRT1cMBYVBIPZ3kR7aoIsIjmY
Capabilities: workflow_sdk: true, indoor_positioning: true
If you don't already know the device id, you can list all of them via the CLI:
$ relay devices
ID
ββββββββββββββββββββββββββ
990007560034567
990007560043210
VIRT1cMBYVBIPZ3kR7aoIsIjmY
And if you need to see the corresponding name for each of these device ids, you can get that list in Dash in the Account -> Users view.
Now you can send the trigger, using the access token, targeting a device as user_id
.
The path part of the URL is /ibot/workflow/
followed by the workflow id, and then with the query parameters subscriber_id
and user_id
(the device id).
In the example using Node and Axios, we are using interceptors to refresh the access token when it expires and invoking a custom HTTP Trigger.
The Relay server will require a User-Agent
header. It doesn't matter what the value is, it simply needs to be present and non-empty.
HTTP trigger:
curl -vv -d '{"action": "invoke"}' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 3c388bb1e69244ec2fc5e2209df3d1cc" \
-H "User-Agent: my_client" \
"https://all-main-pro-ibot.relaysvr.com/ibot/workflow/wf_http_Y4xdLSLW8gJIpGaCjqOSp3?subscriber_id=ee4547e0-aaef-4956-b853-ad0123456789&user_id=990007560034567"
import axios from 'axios'
const _axios = axios.create()
const access_token = await refresh_auth()
_axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`
_axios.interceptors.response.use(function (response) {
return response;
}, async function (error) {
console.log('ERROR')
if(error.response) {
console.log(error.response.data)
console.log(error.response.status)
}
console.log(error.config)
let originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
const token = await refresh_auth()
_axios.defaults.headers.common['Authorization'] = `Bearer ${token}`
return _axios(originalRequest)
}
return Promise.reject(error)
})
try {
const response = await _axios.post(`${process.env.RELAY_HOST}${process.env.WORKFLOW}?subscriber_id=${sub_id}&user_id=${user_id}`,
{
"action": "invoke"
})
if (response.status == 200) {
console.log(`Remote trigger invoked`)
}
} catch (err) {
console.error(err)
}
Fetching device info:
curl -vv -X GET \
-H "Authorization: Bearer 3c388bb1e69244ec2fc5e2209df3d1cc" \
-H "User-Agent: my_client" \
"https://all-main-pro-ibot.relaysvr.com/relaypro/api/v1/device/990007560034567?subscriber_id=ee4547e0-aaef-4956-b853-ad0123456789"
You may have noticed in the above two examples that there is a User-Agent
header in our outbound request. Why is that there? The firewalls around the Relay server require that User-Agent header to be present, but it doesn't matter what the value of it is, it just needs to be non-empty.
This should be everything you need to know to fully authenticate for using the HTTP APIs.
Updated 11 months ago