Authentication
An API key is a pair: a ClientID, which is not confidential, and a secret, which is. You never send the secret with ordinary requests. You exchange the pair for an access token and send the token instead.
Exchange the key for a token
Send the ClientID and secret as HTTP Basic credentials to POST /v1/token:
curl -X POST https://server.api.throughline.dk/v1/token \
-u "$THROUGHLINE_CLIENT_ID:$THROUGHLINE_CLIENT_SECRET"
{ "accessToken": "eyJhbGciOi…", "tokenType": "Bearer", "expiresIn": 900 }
expiresIn is in seconds: a token lasts 15 minutes. A wrong ClientID or secret answers 401 with the code invalid_client, and so does a key that has been revoked.
Use the token
Send the token as a bearer token on every other route:
curl https://server.api.throughline.dk/v1/contacts/user-42 \
-H "Authorization: Bearer $THROUGHLINE_TOKEN"
A missing, malformed or expired token answers 401 with the code unauthenticated. Exchange the key again and repeat the request once. There is no refresh token; the exchange is the refresh.
Exchange once and reuse the token for its 15 minutes, rather than exchanging before every call. The exchange checks the secret against a slow hash on purpose, so it is the most expensive call you can make.
- @throughlinehq/server
- Your own client
The client does all of this for you: it exchanges on the first call, shares one exchange between concurrent calls, and on a 401 exchanges again and replays the request.
const throughline = new ThroughlineClient({
clientId: process.env.THROUGHLINE_CLIENT_ID!,
secret: process.env.THROUGHLINE_CLIENT_SECRET!,
});
Keep the token with its expiry. Exchange when there is no token, when it is within a minute of expiring, and once after a 401. If the second attempt also answers 401, stop: the key has been revoked.
Keep the secret on your server
The secret grants whatever Scopes the key holds, over every Contact in your Tenant. Keep it in your secret store and out of anything a browser downloads. For code that runs in a browser, use a publishable key instead; it can only record Events and carries no secret.
We store only a hash of the secret, so we cannot show it again. If you lose it, create a new key and revoke the old one.