Step 6: Generate keys and get a token
Generate Production keys
- Open your application from Applications in the Developer Portal.
- Open Production Keys and choose Generate Keys.
- Check that the token endpoint shown uses
apim.kairosinnovations.dev. Do not copy an old hostname from a saved screenshot or command.
The Developer Portal shows your Consumer Key and Consumer Secret. Keep the secret private and treat it like a password. Store it in your secret store, never in source code.
The telemetry API has no sandbox endpoint. The gateway rejects a token made from Sandbox Keys with HTTP 403 Forbidden:
{"code":"900901","type":"Status report","message":"Runtime Error","description":"Sandbox key offered to the API with no sandbox endpoint"}
This does not mean your key or secret is wrong. Use Production Keys for both integration testing and live traffic. If you already generated Sandbox Keys, go to Production Keys and generate keys there. You do not need to revoke the Sandbox pair; it just will not work.
Get an access token
Your backend exchanges the consumer key and secret for a short-lived access token. It uses the OAuth 2.0 client credentials grant:
POSTto the token endpointhttps://apim.kairosinnovations.dev/oauth2/token;- send the consumer key and secret with HTTP Basic authentication;
- send the form field
grant_type=client_credentials.
A successful response looks like this:
{
"access_token": "<access token>",
"scope": "default",
"token_type": "Bearer",
"expires_in": 3600
}
expires_inis the token's lifetime in seconds. The 3600 above is an example: always use the value in the real response.- Send the token on every telemetry call as
Authorization: Bearer <access_token>. - Reuse the token until shortly before it expires. Do not request a new token for every batch.
- Keep TLS certificate checks on. Never use cURL's
-koption.
Access tokens explains caching, renewal and credential rotation.
Set the environment variables
The samples on this page and the next read their settings from four environment variables. For the Integration environment, set them like this:
export IFMS_TOKEN_URL='https://apim.kairosinnovations.dev/oauth2/token'
export IFMS_GATEWAY_URL='https://gw.kairosinnovations.dev/api/v1'
export IFMS_CLIENT_ID='<your consumer key>'
export IFMS_CLIENT_SECRET='<your consumer secret>'
- Replace the last two values with your own consumer key and consumer secret. In a real integration, load them from your secret store.
IFMS_GATEWAY_URLis the base address. Do not add/ingest/telemetry: each sample adds it.- The Environments page lists the same URLs.
Sample code
This cURL sample only gets a token. It needs IFMS_TOKEN_URL, IFMS_CLIENT_ID and IFMS_CLIENT_SECRET. Save it as get-token.sh and run it with sh get-token.sh.
The complete Python, JavaScript and Java clients, including their token handling, are on the next step.
- cURL
#!/bin/sh
# Gets an IFMS access token with the OAuth 2.0 client credentials grant.
#
# Integration environment. Set these three variables before running (the
# Environments page lists the values; never hard-code credentials here):
# IFMS_TOKEN_URL token endpoint, https://apim.kairosinnovations.dev/oauth2/token
# IFMS_CLIENT_ID your application's consumer key
# IFMS_CLIENT_SECRET your application's consumer secret
#
# Requires only POSIX sh, curl and sed. Run it: sh get-token.sh
# Prints how long the token is valid for, never the token or the secret.
set -eu
: "${IFMS_TOKEN_URL:?IFMS_TOKEN_URL is not set}"
: "${IFMS_CLIENT_ID:?IFMS_CLIENT_ID is not set}"
: "${IFMS_CLIENT_SECRET:?IFMS_CLIENT_SECRET is not set}"
# The client id and secret go to curl on standard input as a config line
# ("user = id:secret", sent as HTTP Basic auth), so the secret never appears
# in the process list the way a "-u id:secret" argument can. If your secret
# contains a double quote or a backslash, put a backslash in front of it.
token_response=$(curl --silent --show-error --fail \
--config - \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=default" \
"$IFMS_TOKEN_URL" <<EOF
user = "${IFMS_CLIENT_ID}:${IFMS_CLIENT_SECRET}"
EOF
) || {
echo "get-token: the token request failed; check IFMS_CLIENT_ID and IFMS_CLIENT_SECRET" >&2
exit 1
}
# The response is JSON such as {"access_token":"...","token_type":"Bearer",
# "expires_in":3600}, possibly spread over several lines: join them into one
# line, then sed pulls out the two values this script needs.
token_response=$(printf '%s\n' "$token_response" |
sed -e :a -e '$!N' -e '$!ba' -e 's/\n/ /g')
access_token=$(printf '%s' "$token_response" |
sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
expires_in=$(printf '%s' "$token_response" |
sed -n 's/.*"expires_in"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p')
if [ -z "$access_token" ] || [ -z "$expires_in" ]; then
# A wrong host, or http:// instead of https://, typically answers with a
# redirect or an HTML sign-in page; curl does not follow it (no --location).
echo "get-token: the token response has no access_token or expires_in; check IFMS_TOKEN_URL: a wrong host, or http instead of https, answers with a redirect or an HTML page instead of JSON" >&2
exit 1
fi
# Use the token as "Authorization: Bearer <token>" until it expires; renew it
# a minute early so a request never goes out with a token about to lapse.
echo "get-token: got an access token, valid for $expires_in seconds"