Authentication

Request an access token

Exchanges your service account credentials for a short-lived Bearer access token (OAuth 2.0 client credentials grant, RFC 6749 section 4.4). Send the token in the Authorization: Bearer <token> header on API calls.

The request body must be application/x-www-form-urlencoded. Always send credentials in the body, never in the URL. A request that puts client_secret or client_assertion in the query string is rejected, and you should treat that credential as exposed and rotate it. HTTP Basic authentication is not supported: an Authorization: Basic header is refused with 401 invalid_client, even when the body also carries credentials. Each parameter may appear only once, and the body may not exceed 16 KiB.

Client authentication. Your service account uses exactly one of these methods. A credential of the other kind is rejected with invalid_client. Send exactly one credential per request.

client_secret_post: send client_id and client_secret.

private_key_jwt: send client_assertion and client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer. client_id is optional, but if you send it, it must equal the assertion's iss. The assertion is a JWT signed with the private key whose public key is registered for your service account (RFC 7523). It must meet these requirements:

  • Signed with RS256, PS256 or ES256, matching the algorithm registered for the key. The header kid is optional and selects among your registered keys. The header typ, if present, must be JWT or client-authentication+jwt. The crit header is not accepted.
  • iss and sub must both equal your client_id.
  • aud must be exactly one value: https://api.resourcly.com. Do not use the token endpoint URL, which many client libraries default to. It is rejected.
  • exp is required and must be no more than 5 minutes in the future. Clock skew of up to 30 seconds is tolerated. iat and nbf, if present, must not be in the future.
  • jti is required, 1 to 256 characters, and unique per assertion.

Single use. Each assertion can be used once. Presenting the same assertion again returns invalid_client, so generate a fresh assertion (new jti) for every token request. An assertion is not consumed when the request fails without issuing a token (for example invalid_scope, unauthorized_client or a 503), so you may retry with the same one until it expires.

Scope. scope is an optional space-delimited list. If omitted, the token receives every scope granted to your service account. Requesting a scope your service account has not been granted returns invalid_scope. Available scopes: items:read.

Lifetime. The token is valid for the number of seconds in expires_in (currently 15 minutes). No refresh token is issued: request a new token before or after expiry. Tokens stop working immediately if the service account is revoked or its access is changed.

Errors use the RFC 6749 section 5.2 format (error, error_description), except 429:

  • 400 invalid_request: malformed request, wrong content type, a repeated parameter, a missing grant_type, client_secret without client_id, client_assertion without client_assertion_type, both credentials sent, or credentials sent in the URL.
  • 400 unsupported_grant_type: grant_type is anything other than client_credentials.
  • 400 unauthorized_client: API access is not enabled for your organization. Contact support@resourcly.com.
  • 400 invalid_scope: a requested scope has not been granted to your service account.
  • 401 invalid_client: no credential was sent, an Authorization: Basic header was sent, or client authentication failed. A failed authentication is deliberately generic and does not say why (unknown client, wrong secret, bad signature, expired or replayed assertion, revoked account). It carries WWW-Authenticate: Bearer realm="oauth".
  • 429: too many requests. The body is {"error": "rate limit exceeded", "code": "RATE_LIMITED"}; retry after the number of seconds in the Retry-After header.
  • 503 temporarily_unavailable: retry shortly.
post/oauth/token

Response

OK

access_tokenstring

Bearer token to send in the Authorization header

expires_ininteger

seconds until the token expires

scopestring

space-delimited scopes the token carries

token_typestring

always "Bearer"

Example response

{
  "access_token": "eyJhbGciOi...",
  "expires_in": 900,
  "scope": "items:read",
  "token_type": "Bearer"
}

Changes

Changed in 1 of the 12 revisions of this API.1