Machine Authentication
Learn how Wristband SDKs retrieve, cache, and refresh access tokens for machine-to-machine clients.
Machine-to-machine (M2M) authentication lets a backend service call another API on its own behalf, without a user involved. The calling service authenticates with the credentials of a Wristband M2M OAuth2 Client, gets an access token, and sends it as a Bearer token. The receiving API then validates that token.
M2M auth SDKs handle the calling side. They get access tokens from Wristband using the Client Credentials grant type, cache them in memory, and get a new one when the cached token is about to expire. The receiving API validates the tokens with a JWT validation SDK, or with the JWT strategy of a backend server auth SDK's auth middleware.
See JWT Validation for how the receiving API validates access tokens.
Setting Up the M2M Auth SDK
The M2M auth SDK is configured once when your service starts, and the same instance is shared across your service. It needs three values from your Wristband Application:
clientIdandclientSecret: The credentials of your Application's M2M OAuth2 Client.wristbandApplicationVanityDomain: The vanity domain of your Wristband Application.
For example, using the TypeScript M2M Auth SDK:
import { createWristbandM2MClient } from '@wristband/typescript-m2m-auth';
export const wristbandM2MClient = createWristbandM2MClient({
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
wristbandApplicationVanityDomain: process.env.APPLICATION_VANITY_DOMAIN!,
});To call APIs for more than one M2M OAuth2 Client, create a separate instance for each.
M2M Auth SDK Configuration
Setting names may vary by SDK.
| Setting | Required | Default | Description |
|---|---|---|---|
clientId | Yes | N/A | The ID of your Wristband M2M OAuth2 Client. |
clientSecret | Yes | N/A | The secret of your Wristband M2M OAuth2 Client. |
wristbandApplicationVanityDomain | Yes | N/A | The vanity domain of your Wristband Application. |
tokenExpirationBuffer | No | 60 | Seconds subtracted from each access token's expiration time. |
backgroundTokenRefreshInterval | No | Disabled | Seconds between background token refreshes. Must be at least 60 when set. |
Getting an Access Token
Your service asks the SDK for an access token before each request to a protected API, and sends it in the Authorization header. For example, using the TypeScript M2M Auth SDK:
const accessToken = await wristbandM2MClient.getToken();
const response = await fetch('https://api.yourapp.io/orders', {
headers: { Authorization: `Bearer ${accessToken}` },
});When the SDK needs a new token, it calls the Wristband Token Endpoint on your Application's vanity domain with the Client Credentials grant type. The request authenticates with your clientId and clientSecret. For example:
POST https://yourapp-yourcompany.us.wristband.dev/api/v1/oauth2/token
grant_type=client_credentialsThe SDK doesn't use refresh tokens. When a token expires, it requests a new one with the same client credentials.
Getting a Token at Startup
The first request for a token has to wait for the call to Wristband. To avoid that delay on your service's first outgoing request, request a token once while your service starts up, which fills the cache before any traffic arrives.
For example, using the TypeScript M2M Auth SDK:
async function start() {
try {
await wristbandM2MClient.getToken();
} catch (err) {
console.error('Failed to retrieve initial M2M token:', err);
}
app.listen(3000);
}Token Caching
The SDK caches two values in memory:
- Access token: The
access_tokenfrom the Wristband Token Endpoint response. - Expiration time: The token's
expires_inlifetime minus thetokenExpirationBuffer, which defaults to 60 seconds. The buffer makes the SDK get a new token slightly before the current one actually expires, which helps avoid tokens expiring in the middle of an API call.
Each request for a token returns the cached token if it's still valid, and only calls Wristband when the cache is empty or the token is about to expire.
If several parts of your service request a token while a new one is being fetched, they all wait for that same request, so the SDK only calls Wristband once.
The cache isn't persisted. In serverless and edge runtimes, where memory doesn't last between invocations, each cold start fetches a new token.
Background Refresh
By default, the SDK only gets a new token when one is requested and the cached token is about to expire. You can optionally set backgroundTokenRefreshInterval to also get a new token on a fixed interval, independent of request activity. The minimum interval is 60 seconds.
If a background refresh fails, it doesn't throw an error or affect token requests. The next token request gets a new token if the cached one is no longer valid.
Background refresh isn't suitable for serverless and edge runtimes, since the process doesn't persist between requests. In those environments, rely on getting a new token when one is requested instead.
Clearing the Cached Token
If a protected API rejects the access token with a 401 Unauthorized response, your service can clear the cached token. The next token request then gets a new one from Wristband.
For example, using the TypeScript M2M Auth SDK:
if (response.status === 401) {
wristbandM2MClient.clearToken();
}Retries and Errors
If the call to Wristband fails with a server error (5xx), the SDK retries it, up to three attempts in total, waiting 100 milliseconds between attempts. Client errors (4xx) and network failures aren't retried, and the token request fails immediately.
If all attempts fail, the token request throws an error, and your service decides how to handle it.
Updated about 4 hours ago