npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wristband/typescript-m2m-auth

v0.1.1

Published

A runtime-agnostic SDK for Wristband Machine-to-Machine OAuth2 authentication. Works in any environment with a native fetch API.

Downloads

202

Readme


Wristband Machine-to-Machine (M2M) Authentication SDK for TypeScript

npm version number Actions Status License

This TypeScript SDK enables Wristband machine-to-machine (M2M) OAuth2 clients to securely retrieve, cache, and refresh access tokens. Designed for server-to-server communication, it automates M2M token management with zero user interaction and zero runtime dependencies.

Compatible with Node.js, Deno, Bun, Cloudflare Workers, and other TypeScript server runtimes.

You can learn more about how authentication works in Wristband in our documentation:


Table of Contents

Requirements

Usage

1) Installation

# With npm
npm install @wristband/typescript-m2m-auth

# With yarn
yarn add @wristband/typescript-m2m-auth

# With pnpm
pnpm add @wristband/typescript-m2m-auth

2) Wristband Configuration

  1. First, make sure you have a Wristband account set up. You can sign up here.
  2. From the Dashboard home page, add a new Application, and then navigate to the "Application Settings" side menu nav for that application. Copy down the Application Vanity Domain from the top box.
  3. Next, navigate to the "OAuth2 Clients" side nav menu and create a Machine-to-Machine (M2M) OAuth2 Client. Copy down the Client ID and Client Secret.

3) Configure the SDK

First, store your credentials securely. For local development, a .env file works well:

[!NOTE] Never commit secrets to source control. Use environment variables or a secrets manager in production.

CLIENT_ID=<your-client-id>
CLIENT_SECRET=<your-client-secret>
APPLICATION_VANITY_DOMAIN=<your-domain.wristband.dev>

Then, instantiate the client once at module level with the createWristbandM2MClient() factory function so it is shared across requests:

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!,
});

Multiple Instances

If you need to communicate with multiple Wristband Applications or use different OAuth2 clients, simply instantiate the client multiple times:

const wristbandM2MClient01 = createWristbandM2MClient({ ... });
const wristbandM2MClient02 = createWristbandM2MClient({ ... });

4) Prime the Token Cache on Server Startup

Call getToken() during server startup to pre-load the token cache. This avoids a cold-start delay on the first request.

// Express
import express from 'express';
import { wristbandM2MClient } from './auth';

const app = express();

async function start() {
  try {
    await wristbandM2MClient.getToken();
  } catch (err) {
    console.error('[M2M AUTH] Failed to retrieve initial M2M token:', err);
  }

  app.listen(3000);
}

start();

5) Use the Token

Call getToken() before any authenticated downstream request and pass the result as a Bearer token. If a downstream API returns a 401, call clearToken() to force a fresh token on the next call.

async function callProtectedApi() {
  const token = await wristbandM2MClient.getToken();

  const response = await fetch('https://your-api.example.com/protected', {
    headers: { Authorization: `Bearer ${token}` },
  });

  if (response.status === 401) {
    wristbandM2MClient.clearToken();
  }

  return response.json();
}

Token Caching and Refresh

The SDK automatically caches tokens in memory. On each getToken() call, the cached token is returned if still valid. When it expires, a new token is fetched automatically.

Expiration Buffer

A buffer is subtracted from the token's expiration time to ensure the token is refreshed slightly before it actually expires. The default is 60 seconds.

createWristbandM2MClient({
  // ...
  tokenExpirationBuffer: 120, // Refresh 2 minutes before actual expiration
});

Background Refresh

You can optionally enable proactive background refreshing at a fixed interval, independent of request activity:

createWristbandM2MClient({
  // ...
  backgroundTokenRefreshInterval: 900, // Refresh every 15 minutes
});

Background refresh failures are silently swallowed; they will not throw or affect foreground getToken() calls. If the token is still invalid after a failed background refresh, the next getToken() call will fetch a fresh one.

On Node.js, Deno, and Bun, unref() is called on the background timer so it will not prevent the process from exiting cleanly.

[!NOTE] Background refresh is not suitable for serverless or edge runtimes (Cloudflare Workers, AWS Lambda, etc.) where the process does not persist between requests. Avoid setting backgroundTokenRefreshInterval in these environments and rely on getToken()'s built-in lazy refresh instead.

SDK Configuration Options

| Option | Type | Required | Default | Description | | ------ | ---- | -------- | ------- | ----------- | | clientId | string | Yes | — | The client ID of the Wristband M2M OAuth2 Client. | | clientSecret | string | Yes | — | The client secret of the Wristband M2M OAuth2 Client. | | wristbandApplicationVanityDomain | string | Yes | — | The vanity domain of the Wristband application. | | tokenExpirationBuffer | number | No | 60 | Seconds to subtract from the token's expiration for early refresh. Must be >= 0. | | backgroundTokenRefreshInterval | number \| undefined | No | undefined | Seconds between background refresh attempts. undefined disables background refresh. Minimum is 60 seconds when provided. |

API

createWristbandM2MClient(config)

Factory function that creates and returns a new WristbandM2MClient instance.

const client = createWristbandM2MClient({ ... });

WristbandM2MClient

getToken()

Returns a valid access token, fetching a new one if the cache is empty or expired. Concurrent calls while a fetch is in flight are coalesced. Only one HTTP request is made regardless of how many callers are waiting. Retries up to 3 times on 5xx errors with 100ms between attempts. Fails immediately on 4xx or network errors.

const token = await client.getToken();

[!NOTE] In serverless and edge runtimes (Cloudflare Workers, AWS Lambda, etc.), the in-memory token cache does not persist between requests. Each cold start will incur a token fetch. This is expected behaviour; getToken() will still work correctly, it just cannot cache across invocations.

clearToken()

Clears the cached token. The next getToken() call will fetch a fresh one. Use this when a downstream API returns a 401.

client.clearToken();

Runtime-specific Setup

Node.js (20+)

No additional setup required. Install and use as shown above.

Deno

import { createWristbandM2MClient } from 'npm:@wristband/typescript-m2m-auth';

Bun

No additional setup required. Install and use as shown above.

Cloudflare Workers

Instantiate the client outside the request handler to reuse it across requests within the same isolate:

import { createWristbandM2MClient } from '@wristband/typescript-m2m-auth';

const m2mClient = createWristbandM2MClient({
  clientId: env.CLIENT_ID,
  clientSecret: env.CLIENT_SECRET,
  wristbandApplicationVanityDomain: env.VANITY_DOMAIN,
});

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const token = await m2mClient.getToken();
    // ...
  },
};

Related Wristband SDKs

@wristband/typescript-jwt

This SDK can work in tandem with the Wristband TypeScript JWT SDK for JWT validation. It handles JWT signature verification, token parsing, and JWKS key management. Refer to that GitHub repository for more information on JWT validation configuration and options.

Wristband Express M2M Demo App

You can check out the Wristband Express M2M demo app to see this SDK in action. Refer to that GitHub repository for more information.

Questions

Reach out to the Wristband team at [email protected] for any questions regarding this SDK.