Public API authentication
The API uses OAuth 2.0 client credentials, with the client authenticated by a signed JWT (private_key_jwt, RFC 7523). There are no client secrets: you hold a private key, HCM Cafe holds the matching public key.
Client assertion
The assertion is a JWT you sign for each token request.
| Part | Rule |
|---|---|
| Algorithm | ES256 with a P-256 key, or RS256 with an RSA key |
iss | Your client ID |
sub | Your client ID, the same as iss |
aud | https://api.hcmcafe.com/oauth/token, exactly, with no trailing slash |
exp | Required, and at most 5 minutes after the time of the request |
nbf, iat | Recommended. Set them to the current time |
jti | Required, at most 128 characters, and never reused: each assertion can be used once |
The server allows 30 seconds of clock difference. Keep your server's clock synchronised, for example with NTP.
Token request
POST https://api.hcmcafe.com/oauth/token with Content-Type: application/x-www-form-urlencoded:
| Field | Value |
|---|---|
grant_type | client_credentials |
client_assertion_type | urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
client_assertion | The signed assertion |
scope | Optional. Space-separated. Every scope you ask for must be one your client holds. Leave it out to get all of them |
Token response
| Field | Meaning |
|---|---|
access_token | Send it as Authorization: Bearer <token> on every API call |
token_type | Bearer |
expires_in | Seconds until the token expires, currently 600 |
scope | The scopes the token holds |
Cache the token and reuse it for all calls until shortly before it expires, then request a new one. Requesting a token for every call is slower, and the token URL has its own rate limit of 30 requests a minute per source address.
| Status | error | Meaning |
|---|---|---|
| 400 | invalid_request | client_assertion_type or client_assertion is missing or wrong |
| 400 | unsupported_grant_type | grant_type isn't client_credentials |
| 400 | invalid_scope | You asked for a scope your client doesn't hold |
| 401 | invalid_client | The assertion or the client was refused. See Troubleshooting |
| 429 | Too many token requests. Wait for the number of seconds in Retry-After |
For security, invalid_client doesn't say which check failed. HCM Cafe can tell you the reason from its logs if you give the time of the request.
Scopes and tenants
Your client holds the scopes the tenant approved, listed under scopes. A call to a route whose scope the token doesn't hold returns 403. Every call reads and writes only your tenant's data: a record in another tenant returns 404, the same as one that doesn't exist.
Rotate a key
You can rotate without downtime, because a client can hold more than one active key.
- Create a new key pair and send HCM Cafe the new public key.
- Once HCM Cafe confirms it's added, switch your service to the new private key.
- Tell HCM Cafe, and the old key is turned off.
We recommend rotating at least once a year, and straight away if a private key might have been exposed. If a private key is lost or exposed, ask HCM Cafe to turn the key off first, then send a new one.
IP limits
If you send IP ranges when you register, token requests from any other address are refused with invalid_client. The check applies when a token is issued, so keep tokens on the servers that requested them. Tell HCM Cafe before your outbound addresses change.
Revoked or expired clients
HCM Cafe can revoke a client, or register it with an end date. Token requests then fail with invalid_client, and tokens already issued keep working until they expire, at most 10 minutes later.