> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.benchling.com/in-vivo/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.benchling.com/in-vivo/_mcp/server.

# Create a token

POST https://acme-api.invivo.benchling.com/api/public/v1/oauth/token
Content-Type: application/json

Exchanges your client credentials for an access token. This endpoint is itself unauthenticated, and accepts a JSON body rather than the form-encoded body described by RFC 6749.

Reference: https://docs.benchling.com/in-vivo/authentication/oauth-token-create

## Request

### Body (application/json)

This endpoint expects an OAuthTokenRequest.

- `grant_type` ("client_credentials", required) — OAuth2 grant type; must be 'client_credentials'.
- `client_id` (string, required) — Your application's Client ID.
- `client_secret` (string, required) — Your application's Client Secret.

## Response

### 200

An access token was issued.

- `token_type` ("Bearer", required) — How the token must be presented; always 'Bearer'.
- `expires_in` (long, required) — Lifetime of the access token, in seconds from issue.
- `access_token` (string, required) — The signed JWT access token.

## Errors

### 400 Bad Request Error

The request was rejected. Validation failures return a `ValidationErrorResponse`; an unrecognised `X-Studies-Api-Version` header returns an `AuthErrorResponse` with the code `invalid_header`.

- `BadRequestErrorResponse`

### 401 Unauthorized Error

Authentication failed. The body is normally empty; when an otherwise valid access token is missing required claims the body is an `AuthErrorResponse` with the code `invalid_token`.

- `any`

### 429 Too Many Requests Error

A rate limit was exceeded. Retry once the window resets; no `Retry-After` header is sent, so use `X-RateLimit-Reset`.

- `error` ("rate_limit_exceeded", required) — A machine-readable error code.
- `message` (string, required) — A human-readable explanation of the failure.

## Types

### ValidationErrorResponse

Returned when a request body or parameter fails validation.

- `message` (string, required) — A summary of the failure.
- `errors` (map from string to list of string, required) — Failure messages keyed by the offending field, using the field's name as it appears on the wire. Nested fields are dotted, e.g. `schedule.duration`.

### AuthErrorResponse

Returned when a request is rejected during authentication, before it is processed.

- `error` (enum, required) — A machine-readable error code.
  - Allowed values: `invalid_header`, `invalid_token`, `invalid_data`
- `error_description` (string, required) — A human-readable explanation of the failure.

### ProblemDetail

An RFC 9457 problem detail, returned when a request is rejected before it reaches a controller method — most commonly an unparseable or absent JSON body. Unlike the rest of this API, null members are omitted rather than serialised as `null`.

- `title` (string, required) — A short, human-readable summary of the problem type.
- `status` (integer, required) — The HTTP status code, repeated in the body.
- `detail` (string, required) — A human-readable explanation specific to this occurrence.
- `instance` (string, required) — The path of the request that produced the problem.

## Examples

**Request**

```json
{
  "grant_type": "client_credentials",
  "client_id": "ba25944e-2fdb-4742-b09e-130e26c46cf0",
  "client_secret": "WbxNbRMOW48M33BMLQZ71Gj7NMMmWnp7Q1U4pgbR"
}
```

**Response**

```json
{
  "token_type": "Bearer",
  "expires_in": 86400,
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJiYTI1OTQ0ZS0yZmRiLTQ3NDItYjA5ZS0xMzBlMjZjNDZjZjAiLCJzY29wZXMiOlsiKiJdLCJleHAiOjE3ODkxMTE2MTl9.T2gYm9iSjFuS3YwUzFnVDlsWjJqUWs4RmRQczdSbkE"
}
```

**SDK Code**

```python
import requests

url = "https://acme-api.invivo.benchling.com/api/public/v1/oauth/token"

payload = {
    "grant_type": "client_credentials",
    "client_id": "ba25944e-2fdb-4742-b09e-130e26c46cf0",
    "client_secret": "WbxNbRMOW48M33BMLQZ71Gj7NMMmWnp7Q1U4pgbR"
}
headers = {"Content-Type": "application/json"}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://acme-api.invivo.benchling.com/api/public/v1/oauth/token';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: '{"grant_type":"client_credentials","client_id":"ba25944e-2fdb-4742-b09e-130e26c46cf0","client_secret":"WbxNbRMOW48M33BMLQZ71Gj7NMMmWnp7Q1U4pgbR"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```