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

# Connect your own account

> Get an OAuth access token for server-to-server requests to your Middesk account

Use the OAuth 2.0 client credentials grant for server-to-server access to your Middesk account without user sign-in. For access on behalf of a user, use the [authorization-code flow](/authentication/oauth).

## Getting an access token

#### Create an OAuth client

Use your [API key](/build/api-keys) to create a confidential client with `client_credentials` enabled. These settings are available through the API.

**`Create an OAuth client`**

```curl title="Create an OAuth client"
curl https://api.middesk.com/v1/oauth_clients \
  -u "$MIDDESK_API_KEY:" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "My integration",
    "redirect_uri": "https://example.com/oauth/unused",
    "confidential": true,
    "allowed_grant_types": ["client_credentials"]
  }'
```

Replace the example URI with a URL you control. A redirect URI is required to create the client, but this grant does not use it. Store the returned `client_id` and `secret` as `CLIENT_ID` and `CLIENT_SECRET` on your server. If you already have a client with this grant enabled, use its credentials.

#### Request a token

Send a form-encoded request using the client ID and secret as HTTP Basic Auth credentials.

**`Request an access token`**

```curl title="Request an access token"
curl https://api.middesk.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'scope=read_only'
```

Choose an [access scope](/authentication/oauth#make-api-requests); if omitted, `scope` defaults to `read_write`. You can send `client_id` and `client_secret` in the form body instead of using Basic Auth.

The response uses the [shared token fields](/authentication/oauth#token-responses) and includes `expires_in`. Tokens expire after one hour by default. Use `expires_in` to determine when to request a new token. This grant does not issue refresh tokens.

#### Make an API request

Follow the shared [API request example and token restrictions](/authentication/oauth#make-api-requests). Machine tokens also cannot invite or remove account users, create or remove affiliate users, or create, remove, or reinvite partner users.

## Authenticating with a private key

If your integration uses `private_key_jwt`, send a signed JWT assertion in place of the client secret.

Create the client with `token_endpoint_auth_method: "private_key_jwt"` and `jwks` containing a `keys` array of public JSON Web Keys. The client must be confidential and allow `client_credentials`. Give each public key a unique `kid` and keep private keys on your server.

Use your JWT library to sign an assertion with these values:

| Field        | Value                                               |
| :----------- | :-------------------------------------------------- |
| Header `alg` | Use `RS256` with an RSA key.                        |
| Header `kid` | The ID of the registered public key.                |
| `iss`, `sub` | Your client ID.                                     |
| `aud`        | `https://api.middesk.com/oauth/token`               |
| `iat`        | Current Unix time in seconds.                       |
| `exp`        | Expiration time, at most 600 seconds after `iat`.   |
| `jti`        | A unique value for each request, including retries. |

**`Request a token with a signed assertion`**

```curl title="Request a token with a signed assertion"
curl https://api.middesk.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'scope=read_only' \
  --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
  --data-urlencode "client_assertion=$CLIENT_ASSERTION"
```

Do not send a client secret with the assertion. Each assertion can be used once; the token response and API usage are the same as above.

## Revoking access

Use the shared [revocation request](/authentication/oauth#revoke-access). For `private_key_jwt`, replace Basic Auth with `client_assertion_type` and a fresh `client_assertion`, using the same audience as the token request.

Disabling the grant or removing a signing key does not invalidate tokens already issued.

> **Get a demo**
>
> Contact your account manager or [contact sales](https://www.middesk.com/contact-sales) to inquire about access.

## Next steps

#### [Authorize access for a user](/authentication/oauth)

Connect to a Middesk account on a user's behalf.

#### [Handle API errors](/build/status-codes-errors)

Review API response codes and error messages.