Avnology ID
SDKsTypeScript SDKOAuth 2.1

Client Credentials

Machine-to-machine authentication with the client credentials grant using the TypeScript SDK.

Client Credentials

The client credentials grant provides machine-to-machine (M2M) authentication. No user interaction is required -- the client authenticates using its own credentials (client ID + secret or API key).

clientCredentials()

Obtain an access token using the client credentials grant.

client.oauth.clientCredentials(params: ClientCredentialsParams): Promise<TokenSet>

Parameters

NameTypeRequiredDescription
scopesstring[]yesOAuth scopes to request
audiencestringnoTarget API audience

Returns

Promise<TokenSet> -- Access token (no refresh token -- request new tokens as needed).

Basic usage

import { AvnologyId } from "@avnology/sdk-typescript";

// Confidential client (server-side only -- never expose secret in browser)
const client = new AvnologyId({
  baseUrl: "https://api.id.avnology.com",
  clientId: "app_backend_service",
  clientSecret: "sk_live_...",
});

const tokens = await client.oauth.clientCredentials({
  scopes: ["users:read", "organizations:read"],
});

console.log(tokens.accessToken);  // "eyJhbGciOi..."
console.log(tokens.expiresIn);    // 3600 (1 hour)
console.log(tokens.tokenType);    // "Bearer"
console.log(tokens.scope);        // "users:read organizations:read"

Using the token to call APIs

// Use the access token to call the Avnology ID Admin API
const response = await fetch("https://api.id.avnology.com/v1/users", {
  headers: {
    Authorization: `Bearer ${tokens.accessToken}`,
  },
});

const users = await response.json();

Service-to-service with API key

For service accounts, use an API key instead of client credentials.

const client = new AvnologyId({
  baseUrl: "https://api.id.avnology.com",
  apiKey: "ak_live_...",
});

// API key authenticates all requests automatically -- no token exchange needed
const users = await client.admin.listUsers({ pageSize: 50 });

Token caching pattern

Client credentials tokens are short-lived. Cache and reuse them until they expire.

class TokenCache {
  private token: TokenSet | null = null;

  constructor(private client: AvnologyId) {}

  async getToken(scopes: string[]): Promise<string> {
    if (this.token && new Date(this.token.expiresAt) > new Date()) {
      return this.token.accessToken;
    }

    this.token = await this.client.oauth.clientCredentials({ scopes });
    return this.token.accessToken;
  }
}

const cache = new TokenCache(client);

// Reuses cached token until it expires
const token = await cache.getToken(["users:read"]);

Common errors

Error classHTTP statusWhen
InvalidClientError401Wrong client ID or secret
InvalidScopeError400Requested scope not allowed for this client
RateLimitError429Too many token requests

See also

On this page