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
| Name | Type | Required | Description |
|---|---|---|---|
scopes | string[] | yes | OAuth scopes to request |
audience | string | no | Target 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 class | HTTP status | When |
|---|---|---|
InvalidClientError | 401 | Wrong client ID or secret |
InvalidScopeError | 400 | Requested scope not allowed for this client |
RateLimitError | 429 | Too many token requests |
See also
- Token exchange -- Delegation and impersonation
- Device flow -- Device authorization
- Service accounts -- API key management