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
- Navigate to Service Accounts in the left sidebar
- Click Create Service Account
- Enter a name and description
- Select the scopes your service needs
- Click Create — you'll receive a and
clientIdclientSecret
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_credentialscurl -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:
| Scope | Description |
|---|---|
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:
| Method | Endpoint | Scope Required | Description |
|---|---|---|---|
GET | /api/v1/m2m/whoami | Any | Verify 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/nodeZewstIDServiceAccountimport { 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:
| Endpoint | Limit |
|---|---|
POST /oauth/token | 30 requests/minute per client |
GET /m2m/* | 100 requests/minute per client |
POST/PATCH /m2m/* | 30 requests/minute per client |
DELETE /m2m/* | 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
- Least privilege — Request only the scopes your service needs
- Rotate credentials — Rotate secrets every 90 days
- Cache tokens — Don't request a new token for every API call
- Handle expiration — Check and refresh before expiry
expires_in - Secure storage — Store credentials in environment variables or a secrets manager, never in source code
- Monitor usage — Check the audit log for unexpected access patterns
Next Steps
- Agent Authentication — Register AI agents with trust levels
- Delegation & A2A — Agent-to-agent token exchange
- Node.js SDK Reference — class docs
ZewstIDServiceAccount
Was this page helpful?
Let us know how we can improve our documentation