Skip to content
Hexel StudioDocs

Authenticate to the API

Send an API key, exchange it for an access token, use OAuth client credentials, and refresh tokens for people.

On this page

Every call to https://api.hexelstudio.com/v1/... must say who is calling. Scripts, servers and CI jobs authenticate as a service user, with an API key or an OAuth client. People sign in to Hexel Studio with their Hexel account, and the console gets tokens for them.

MethodBest forWhat you send to the API
API key in a headerScripts, quick tests, low request ratesX-API-Key: $API_KEY
API key exchanged for a tokenServices that make many callsAuthorization: Bearer $ACCESS_TOKEN
OAuth client credentialsServices and tools that speak OAuth 2.0Authorization: Bearer $ACCESS_TOKEN
Role sessionTemporary access to a role's permissionsAuthorization: Bearer $ACCESS_TOKEN

An access token is a short-lived signed token for one identity in one organization. Tokens are issued by the token service at https://sts.hexelstudio.com. See Tokens for lifetimes and claims.

Send an API key directly

Send the key in the X-API-Key header. Hexel Studio checks the key at the edge, exchanges it for an access token of the key's service user, and passes the request on with that token.

Bash
curl https://api.hexelstudio.com/v1/workspaces \
  -H "X-API-Key: $API_KEY"
  • The organization comes from the key. You don't need X-Organization-Id. If you send it, it must be the key's organization.
  • If a request carries both Authorization: Bearer ... and X-API-Key, the bearer token is used and the key is ignored.
  • Hexel Studio removes X-API-Key from the request before it reaches the service that handles it.
  • Some product APIs accept only a bearer token. If a key gets 401 on a route where a token works, exchange the key first.

Errors from the API key check have this shape:

JSON
{"error": {"code": "403", "message": "X-Organization-Id does not match the API key's organization."}}
StatusCause
401The key is unknown, expired or revoked, or its service user is disabled or deleted.
403X-Organization-Id names a different organization than the key's.
429Too many invalid API keys from your IP address (20 a minute), or a rate limit was exceeded. Wait for the Retry-After seconds.
503API key checking is temporarily unavailable. Retry with backoff.

Exchange an API key for an access token

POST https://sts.hexelstudio.com/token with the key in X-API-Key. The body is optional for this grant. If you send one, set grant_type to api_key.

Bash
curl -X POST https://sts.hexelstudio.com/token \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"grant_type": "api_key"}'
JSON
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "refresh_token": "",
  "token_type": "Bearer",
  "expires_in": 900
}
access_tokenstring

The access token. Send it as Authorization: Bearer <access_token>.

refresh_tokenstring

Always empty for this grant. Exchange the key again when the token expires.

token_typestring

Always Bearer.

expires_ininteger

Seconds until the token expires: 900 (15 minutes).

Then call the API with the token:

Bash
curl https://api.hexelstudio.com/v1/workspaces \
  -H "Authorization: Bearer $ACCESS_TOKEN"

An unknown, expired or revoked key, or a key whose service user is disabled, gets 401 with {"error": "invalid api key"}.

Use OAuth client credentials

An OAuth client is a client_id and client_secret pair that belongs to a service user. Exchange it for an access token with the OAuth 2.0 client_credentials grant.

curl -X POST https://sts.hexelstudio.com/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "'"$CLIENT_ID"'",
    "client_secret": "'"$CLIENT_SECRET"'"
  }'
grant_typestringbodyrequired

client_credentials.

client_idstringbodyrequired

The OAuth client's ID, for example client_....

client_secretstringbodyrequired

The client secret, shown once when you create or rotate the client.

The token endpoint accepts a JSON body (Content-Type: application/json) or a form body (Content-Type: application/x-www-form-urlencoded). Instead of the body, you can send the client ID and secret with HTTP Basic authentication (Authorization: Basic ..., the ID and secret form-URL-encoded first, as RFC 6749 describes). Use one method: credentials in both places are refused with 400.

The response has the same fields as the API key exchange: a 15-minute access token, token_type Bearer, expires_in 900 and an empty refresh_token. Request a new token when it expires.

StatusBodyCause
400{"error": "client_id and client_secret required"}A field is missing.
400{"error": "use one client authentication method: HTTP Basic or the request body"}Credentials sent both ways.
401{"error": "invalid client credentials"}Unknown, revoked or expired client, wrong secret, or the service user is disabled.

Get a role session directly

With an API key or client credentials, you can ask for a session of a role in the same call. Add resource with the role ID. The role's trust policy must allow your service user.

Bash
curl -X POST https://sts.hexelstudio.com/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "'"$CLIENT_ID"'",
    "client_secret": "'"$CLIENT_SECRET"'",
    "resource": "<role-id>",
    "session_name": "nightly-export"
  }'

The response is a role session, described in Assume a role. People and service users that already hold an access token use token exchange instead, on the same page.

People: sign in with a Hexel account

People sign in to the console with their Hexel account. The console exchanges the sign-in for a Hexel Studio access token and a refresh token for the organization you select, and refreshes it for you.

Exchanging a Hexel account sign-in for a token from your own application is not open for self-service. Contact Hexel Studio if you need it. For automation, use a service user.

Refresh tokens

Only a sign-in with a Hexel account returns a refresh token. API keys and OAuth clients never do: exchange the credential again instead. Role sessions can't be refreshed: assume the role again.

To refresh, POST https://sts.hexelstudio.com/refresh with the refresh token:

Bash
curl -X POST https://sts.hexelstudio.com/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "'"$REFRESH_TOKEN"'"}'
JSON
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "refresh_token": "<new-refresh-token>",
  "token_type": "Bearer",
  "expires_in": 900
}
  • Each refresh token works once. The response carries a new one; store it and discard the old one.
  • A refresh keeps the organization. If you send X-Organization-Id with a different organization, the request fails with 400. Sign in again to switch.
  • A refresh fails with 401 after the refresh token's 30-day lifetime, after the sign-in session's deadline, or once the account is suspended. It fails with 403 if the person is no longer an active member of the organization.
  • expires_in can be under 900 when the sign-in session ends sooner.

To sign out, POST https://sts.hexelstudio.com/revoke with {"refresh_token": "..."}. This ends every refresh token of that person's account, in every organization, and answers {"revoked": true}. Access tokens already issued stay valid until they expire. See Tokens for lifetimes and the sign-in deadline.

Token endpoint limits

POST /token issues at most 60 tokens a minute for each credential: each API key, each OAuth client, each person signing in, and each user, service user or role that exchanges an access token for a role session. The count resets at the start of each minute. Over the limit, you get:

JSON
{"error": "rate_limited", "error_description": "too many tokens issued for this credential; retry later"}

with status 429 and a Retry-After header in seconds. Cache tokens and reuse them until they are close to expiry. See Limits for the API's other rate limits.

Next steps