Skip to main content

M2M (Machine-to-Machine) Authentication

Machine-to-machine authentication allows your backend services, cron jobs, and automation scripts to securely call the ZewstID API without user interaction.

Overview

M2M authentication uses the OAuth 2.0 Client Credentials grant. Your service authenticates with a client ID and secret, and receives an access token scoped to specific permissions.

Your Service ZewstID API │ │ │ POST /oauth/token │ │ grant_type=client_credentials│ │ client_id=xxx │ │ client_secret=yyy │ │ ─────────────────────────► │ │ │ │ { access_token: "eyJ..." } │ │ ◄───────────────────────── │ │ │ │ GET /api/v1/m2m/users │ │ Authorization: Bearer eyJ... │ │ ─────────────────────────► │ │ │ │ { users: [...] } │ │ ◄───────────────────────── │

Creating a Service Account

Via the Developer Portal

  1. Navigate to Service Accounts in the left sidebar
  2. Click Create Service Account
  3. Enter a name and description
  4. Select the scopes your service needs
  5. Click Create — you'll receive a
    clientId
    and
    clientSecret

Important: Save the client secret immediately. It is only shown once.

Via the API

curl -X POST https://api.zewstid.com/api/v1/service-accounts \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "My Backend Service", "description": "Handles nightly user sync", "scopes": ["users:read", "users:write"] }'

Response:

{ "id": "sa_abc123", "clientId": "sa-my-backend-service", "clientSecret": "zs_secret_xxxxx", "name": "My Backend Service", "scopes": ["users:read", "users:write"], "createdAt": "2026-02-20T10:00:00Z" }

Getting an Access Token

Use the

client_credentials
grant to obtain an access token:

curl -X POST https://api.zewstid.com/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "client_credentials", "client_id": "sa-my-backend-service", "client_secret": "zs_secret_xxxxx", "scope": "users:read" }'

Response:

{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "scope": "users:read" }

Tokens expire after 1 hour by default. Your service should request a new token before the current one expires.

Scope System

Scopes control what your service account can access:

ScopeDescription
users:read
List and get user profiles
users:write
Create and update users
users:admin
Delete users, manage credentials
orgs:read
List organizations and members
orgs:write
Create and manage organizations
analytics:read
Read authentication analytics
agents:read
List and view agents
agents:write
Register and manage agents
delegations:read
View delegation requests
delegations:write
Create and manage delegations

Request only the scopes your service needs. You can update scopes later via the portal or API.

M2M API Endpoints

Once you have an access token, use it to call the M2M API:

MethodEndpointScope RequiredDescription
GET
/api/v1/m2m/whoami
AnyVerify token and get service identity
GET
/api/v1/m2m/users
users:read
List users with pagination
GET
/api/v1/m2m/users/:id
users:read
Get user by ID
POST
/api/v1/m2m/users
users:write
Create a new user
PATCH
/api/v1/m2m/users/:id
users:write
Update user profile
DELETE
/api/v1/m2m/users/:id
users:admin
Delete a user
GET
/api/v1/m2m/users/:id/sessions
users:admin
List user sessions
DELETE
/api/v1/m2m/users/:id/sessions
users:admin
Revoke all sessions
GET
/api/v1/m2m/orgs
orgs:read
List organizations
GET
/api/v1/m2m/orgs/:id
orgs:read
Get organization
GET
/api/v1/m2m/orgs/:id/members
orgs:read
List organization members
GET
/api/v1/m2m/analytics/overview
analytics:read
Authentication analytics
GET
/api/v1/m2m/analytics/events
analytics:read
Auth event log
GET
/api/v1/m2m/analytics/users/active
analytics:read
Active user metrics

Node SDK Usage

The

@zewstid/node
SDK provides a
ZewstIDServiceAccount
class for M2M authentication:

import { ZewstIDServiceAccount } from '@zewstid/node'; const serviceAccount = new ZewstIDServiceAccount({ domain: 'auth.zewstid.com', clientId: process.env.ZEWSTID_SA_CLIENT_ID!, clientSecret: process.env.ZEWSTID_SA_CLIENT_SECRET!, scopes: ['users:read', 'users:write'], }); // Get a token (automatically cached and refreshed) const token = await serviceAccount.getToken(); // Use the token const res = await fetch('https://api.zewstid.com/api/v1/m2m/users', { headers: { Authorization: `Bearer ${token}` }, }); const users = await res.json();

The SDK handles token caching, automatic refresh, and retry logic.

Credential Rotation

Rotate your service account credentials periodically for security:

curl -X POST https://api.zewstid.com/api/v1/service-accounts/sa_abc123/rotate \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{ "clientId": "sa-my-backend-service", "clientSecret": "zs_secret_new_yyyyy", "rotatedAt": "2026-02-20T12:00:00Z" }

The old secret is invalidated immediately. Update your service configuration with the new secret.

Rate Limits

M2M endpoints have the following rate limits:

EndpointLimit
POST /oauth/token
30 requests/minute per client
GET /m2m/*
(read)
100 requests/minute per client
POST/PATCH /m2m/*
(write)
30 requests/minute per client
DELETE /m2m/*
(admin)
10 requests/minute per client

Rate limit headers are included in every response:

X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1708420800

Best Practices

  1. Least privilege — Request only the scopes your service needs
  2. Rotate credentials — Rotate secrets every 90 days
  3. Cache tokens — Don't request a new token for every API call
  4. Handle expiration — Check
    expires_in
    and refresh before expiry
  5. Secure storage — Store credentials in environment variables or a secrets manager, never in source code
  6. Monitor usage — Check the audit log for unexpected access patterns

Next Steps

Was this page helpful?

Let us know how we can improve our documentation