> 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.

# OAuth 2.0 authentication

> Let users authorize your application to access the Middesk API on their behalf

OAuth 2.0 lets your application access the Middesk API on behalf of a Middesk user who signs in and authorizes it. Use OAuth when your application needs to make API requests in a user's account. [API keys](/build/api-keys) authenticate your own server's requests to your own account.

## Create an OAuth client

In the Dashboard, open **Settings** and select **Credentials** under **Developer**, or open the [Credentials page](https://app.middesk.com/settings/credentials). The **OAuth** section lets you manage clients. Each account can have up to 5 OAuth clients.

![OAuth section on the Credentials page](/_fern-img/57d243a9a1fc9bf08dd7589476917e42fa1c7e1a1e3a65dd0b63209232d450eb.webp)

#### Start adding a client

Select **Add New Client** in the **OAuth** section.

#### Enter the client details

In the **Add New OAuth Client** modal, enter the **Redirect URI** that receives authorization responses and, optionally, a **Name**, then select **Add**.

![Add New OAuth Client form](/_fern-img/ab5254ec5476e4d7ed750fc834a394277753975cdbe3859d087f11f773d087aa.webp)

#### Copy and store the credentials

Copy the **Client ID** and **Secret** from the **OAuth** section. Keep the secret on your server and do not expose it in browser code or source control.

## Redirect users to Middesk

Send the user's browser to `GET https://app.middesk.com/oauth/authorize` with these query parameters:

| Parameter       | Required | Description                                                                                                                                                                     |
| :-------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `client_id`     | Yes      | The client ID from the Dashboard.                                                                                                                                               |
| `redirect_uri`  | Yes      | The redirect URI registered for the client. It must match exactly.                                                                                                              |
| `response_type` | Yes      | Set to `code`.                                                                                                                                                                  |
| `scope`         | No       | A space-separated list containing `read_only` or `read_write`. If omitted, the token has read-only access. Use `read_write` when your application needs to make write requests. |
| `state`         | No       | A random value that Middesk returns unchanged. Use it to protect against cross-site request forgery (CSRF).                                                                     |

Generate a unique `state` value for each authorization request and verify it when Middesk redirects back to your application.

**`Authorize request`**

```text title="Authorize request"
https://app.middesk.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&response_type=code&scope=read_only&state=YOUR_RANDOM_STATE
```

If the user is not signed in, Middesk shows its sign-in page. Middesk does not show a separate consent screen. After the user signs in, Middesk authorizes your client for the user's account and redirects back to your application.

Middesk shows an authorization error page if the `client_id` is unknown or the `redirect_uri` does not match the client's registered URI.

## Handle the redirect

Middesk redirects the user's browser to your registered redirect URI with the authorization code and the `state` value, if you sent one:

**`Authorization callback`**

```text title="Authorization callback"
https://app.example.com/oauth/callback?code=AUTHORIZATION_CODE&state=YOUR_RANDOM_STATE
```

Compare the returned `state` with the value you sent. Reject the callback if they do not match. Authorization codes are single-use and expire after 10 minutes.

If the requested scope is invalid, Middesk redirects back with `error=invalid_scope` and an `error_description`.

## Exchange the code for an access token

Send a form-encoded `POST` request to `https://api.middesk.com/oauth/token` with these parameters:

| Parameter       | Required | Description                                                       |
| :-------------- | :------- | :---------------------------------------------------------------- |
| `grant_type`    | Yes      | Set to `authorization_code`.                                      |
| `code`          | Yes      | The authorization code from the callback.                         |
| `redirect_uri`  | Yes      | The same redirect URI you sent in the authorization request.      |
| `client_id`     | Yes      | Provide this in the form body or as the HTTP Basic Auth username. |
| `client_secret` | Yes      | Provide this in the form body or as the HTTP Basic Auth password. |

The following example uses HTTP Basic Auth to send the client credentials.

**`Exchange an authorization code`**

```curl title="Exchange an authorization code"
curl https://api.middesk.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode "code=$AUTHORIZATION_CODE" \
  --data-urlencode 'redirect_uri=https://app.example.com/oauth/callback'
```

Middesk returns the access token, its scope, and the account ID:

**`Token response`**

```json title="Token response"
{
  "access_token": "9f2b1d7c6a0e4b8f3d5c2a1e",
  "token_type": "bearer",
  "scope": "read_only",
  "account_id": "2f0d6a2e-3d18-4e8a-b9f1-72c4e6a8d031"
}
```

Common token errors include:

* `invalid_client` (`401`) when the client credentials are incorrect.
* `invalid_grant` (`400`) when the code expires, has already been used, or the redirect URI does not match.

## Make API requests

Send the access token in the `Authorization` header when you call the Middesk API:

**`Get businesses`**

```curl title="Get businesses"
curl https://api.middesk.com/v1/businesses \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Middesk processes requests as the user who authorized the client, and the account's IP allowlist applies. Tokens with the `read_only` scope can make `GET` requests. Write requests require the `read_write` scope. Other methods sent with a `read_only` token return `403` with the message `The request requires higher privileges than provided by the access token.`

## Revoke access

Revoke an access token when your application no longer needs it. Access tokens issued for your OAuth client do not expire. Send a form-encoded `POST` request to `https://api.middesk.com/oauth/revoke` with client authentication and the token to revoke:

**`Revoke an access token`**

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

With valid client authentication, Middesk returns `200` even if the token is unknown. Revoking a token removes its authorization. Deleting the OAuth client in the Dashboard invalidates all of its tokens.

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

## Next steps

#### [API keys](/build/api-keys)

Authenticate your server's requests to your account with API keys.

#### [Status codes and errors](/build/status-codes-errors)

Review the status codes and error formats returned by the Middesk API.

#### [Security](/security)

Explore Middesk's security features and certifications.