- Purpose
- Establish a safe pattern for machine-to-machine access from an integration layer.
- Prerequisites
- Integration client issued for the sandbox
- Server-side secret storage
- Architecture
- The integration layer exchanges client credentials for a short-lived bearer token, caches it in memory until shortly before expiry, and attaches it to every request. Browsers never see the client secret or the token.
Configuration
| Token endpoint | POST /api/v1/auth/token |
| Lifetime | 3600s (example) |
| Scopes | users.write assignments.write results.read certificates.read webhooks.write |
Implementation steps
- 01Store client_id and client_secret in a server-side secret manager.
- 02Request a token with grant_type=client_credentials and the minimum scopes required.
- 03Cache the token; refresh at 80% of its lifetime.
- 04Retry once on 401 with a fresh token before surfacing an error.
- 05Rotate secrets on a schedule and support two active credentials during rotation.
Examples
Token request
bash
curl -X POST "https://sandbox.integration-lab.local/api/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"$CLIENT_ID","client_secret":"$CLIENT_SECRET","scope":"users.write assignments.write"}'Testing procedure
- Call a protected endpoint without a scope and assert 403
- Expire the cached token and assert transparent refresh
Troubleshooting
401 invalid_client
Credentials belong to a different environment. Sandbox and production clients are distinct.
Intermittent 401
Clock skew or cached expired token. Refresh proactively.