---
title: "Issue an access token from client credentials"
method: POST
path: "/oauth/token"
tags: ["Authentication"]
---

# Issue an access token from client credentials

`POST /oauth/token`

## Request

- Base URL: `https://api.kontainer.com/jsonapi/v2`
- URL: `https://api.kontainer.com/jsonapi/v2/oauth/token`
- Auth: none required
- TypeScript: <https://skmtc.dev/kontainer/apis/kontainer-api-documentation/docs/oauth/token/post.ts> (a function with typed inputs; its response is checked against the schema)

Issues the access token every other endpoint authenticates with. One grant:

**`grant_type=client_credentials`** — exchanges the `client_id` and `client_secret` created
in Settings › Client credentials (the secret is shown only once) for an access token.

No refresh token is issued. When the token expires, call this endpoint again with the same
`client_id` and `client_secret` — they do not expire, and only change if you renew the
secret in Settings.

The response carries `expires_at`, the absolute expiry as an ISO 8601 timestamp in UTC,
rather than the `expires_in` duration RFC 6749 defines. Send the access token as
`Authorization: Bearer <access_token>` and cache it until `expires_at` — this endpoint has
a tighter rate limit than the rest of the API, so minting a token per request will trip it.

Once the token is past `expires_at`, the API answers `401` with the error code
`token_expired` and a `WWW-Authenticate: Bearer error="invalid_token"` header. That code
means only that: the credential is still good, so mint a new token and retry. A wrong or
revoked credential answers `invalid_client` from this endpoint instead.

Responses use the same `application/vnd.api+json` content type as the rest of the API, but the
request does not have to: `application/vnd.api+json`, `application/json` and form-encoded all
work, so a standard OAuth2 client can use this endpoint.

Deleting or renewing a credential in Settings invalidates its tokens immediately.

## Request body

- object
  - `grant_type` 'client_credentials', required
  - `client_id` string, required
  - `client_secret` string, required

## Response `200`

success

- ClientCredentialToken
  - `token_type` string
  - `expires_at` string, date-time: Absolute expiry of the access token, ISO 8601 in UTC. Mint a new token on or before this instant.
  - `access_token` string

## Other responses

- `400`: invalid_request or unauthorized_client
- `401`: invalid_client — unknown client id, wrong secret, or a revoked credential
- `429`: Too Many Requests

---

[API](https://skmtc.dev/kontainer/apis/kontainer-api-documentation.md) - [All operations](https://skmtc.dev/kontainer/apis/kontainer-api-documentation/llms.txt) - [OpenAPI document](https://skmtc.dev/kontainer/apis/kontainer-api-documentation/revisions/b80a5167e09a?raw)
