Machine-to-machine API access
An M2M client represents a backend service. It authenticates with its own credential and can request only explicitly granted API permissions. No person signs in.
Configure and run
Section titled “Configure and run”- Create an API resource with a stable audience, for example
https://api.example.test/billing, and permissioninvoices:read. - Create a Machine to machine client and grant that API and permission in the guided setup. Review the selected client under API Access.
- Store the one-time client secret on the service’s server. Copy its client ID and issuer.
- Follow example setup, setting
OATHVERA_RESOURCEandOATHVERA_SCOPE=invoices:read. - Run
npm run m2m. The example requests a token, checks the first permission, prints a success message without the token, and revokes the token.
If API setup was deferred, finish it before requesting tokens. A credential by itself grants no API permissions.
Request a token
Section titled “Request a token”POST <issuer>/oauth2/tokenAuthorization: Basic <encoded-client-id-and-secret>Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&resource=https%3A%2F%2Fapi.example.test%2Fbilling&scope=invoices%3AreadTypical response, with the token deliberately replaced:
{ "access_token": "<opaque-access-token>", "token_type": "Bearer", "expires_in": 300, "scope": "invoices:read"}The Basic header supplies the client ID; a redundant body client_id, if provided, must match. Use one resource and a nonempty, unique, space-separated permission list. Identity scopes such as openid, profile, email and offline_access are invalid for M2M. A Server web application client cannot use this grant merely because it also has a secret.
Enforce access at the API
Section titled “Enforce access at the API”Your service sends the access token to your API as Authorization: Bearer <token>. Your API sends it to POST <issuer>/authorization/check, using the API’s configured resource and the permission required by its handler. For workloads, organization_id must be null.
{ "resource": "https://api.example.test/billing", "permission": "invoices:read", "organization_id": null}Permit the operation only when the response is HTTP 200 with allowed: true. Workload responses also identify principal_type: "workload", client_id, application_id and tenant_id. If your API accepts only a particular service, compare that returned client ID to a server-configured allowlist. See the permission-check helper.
The API, not the calling service, owns this check. The example calls it directly only to prove the integration. Never accept a caller’s claim that it already checked its token.
Lifecycle
Section titled “Lifecycle”Access tokens last five minutes. M2M has no refresh token or ID token; request another access token when needed. Cache a service token for less than its reported lifetime and avoid a request for every operation. Permission checks must still reflect current authority; do not cache successful authorization decisions.
Revoking the token ends that token. Revoking or expiring its credential also ends the service token’s authority. Changing or disabling its API, grant or client invalidates captured authority; re-enabling those records does not resurrect older service tokens. Use credential rotation for a planned handover.
M2M is not an organization member and does not inherit user roles, social login, MFA or branding. The service and API must still enforce their own business and data boundaries. Workload identity here does not include agent delegation, impersonation or token exchange.