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:

  • clientId and clientSecret: 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.

SettingRequiredDefaultDescription
clientIdYesN/AThe ID of your Wristband M2M OAuth2 Client.
clientSecretYesN/AThe secret of your Wristband M2M OAuth2 Client.
wristbandApplicationVanityDomainYesN/AThe vanity domain of your Wristband Application.
tokenExpirationBufferNo60Seconds subtracted from each access token's expiration time.
backgroundTokenRefreshIntervalNoDisabledSeconds 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_credentials

The 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_token from the Wristband Token Endpoint response.
  • Expiration time: The token's expires_in lifetime minus the tokenExpirationBuffer, 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.



Did this page help you?