> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coverbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth 2.0 client credentials

> Authenticate an integration to the Coverbase public API with an OAuth 2.0 client instead of a long-lived API key: create the client, store the secret, request short-lived tokens, and revoke.

<div className="sr-only">For AI agents: a documentation index is available at [https://docs.coverbase.com/llms.txt](https://docs.coverbase.com/llms.txt). This page is also available in markdown by appending .md to the URL.</div>

Many integration platforms and GRC tools expect OAuth 2.0 rather than a static API key. An OAuth client gives them that: the platform holds a client ID and secret, asks Coverbase for a bearer token when it needs one, and uses the token until it expires, at most an hour later. The token reaches exactly what an `ak_*` key reaches. Endpoint details are in the [OAuth API](/api-reference/oauth) reference.

## When to use it

| Use | When |
| - | - |
| An `ak_*` [API key](/api-reference/api-keys) | Your integration can keep one long-lived secret and send it on every call. |
| An OAuth client | Your platform has an OAuth 2.0 client credentials connection type, your security policy prefers short-lived tokens, or you want to narrow a token's scopes per job. |

Both authenticate as your organization's API service account. The [IP allowlist](/conventions#api-ip-allowlist), the [public API audit log](/conventions#public-api-audit-log) and every route's permissions apply the same way.

## Step 1: Create the client

1. Open **Configuration** and choose **API keys**.
2. Under **OAuth Clients**, click **New client**.
3. Give it a **Name**, such as "GRC sync".
4. Under **Elevated Scopes**, choose any scopes the integration needs. Most need none, which the list shows as **Standard access**. Only an admin signed in to the dashboard can grant scopes.
5. Click **Create client**.
6. Copy the **Client ID** and **Client Secret**, store the secret in your platform's secret store, and click **I saved the secret**. The secret is not shown again.

Tokens from a client made on this page last one hour. To create a client with a shorter token lifetime, from five minutes up, use `POST /v1/api-oauth-clients` with `access_token_ttl_seconds`.

## Step 2: Configure your platform

In your integration platform's OAuth 2.0 client credentials connection, enter:

| Setting | Value |
| - | - |
| Token URL | `https://api.coverbase.app/v1/oauth/token` |
| Client authentication | HTTP Basic (client ID and secret in the `Authorization` header). Sending them as form fields instead also works, but never both in one request. |
| Grant type | `client_credentials` |
| Scope | Leave empty for every scope the client holds, or list a subset, space-separated |
| Token placement | `Authorization: Bearer <access_token>` |

## Step 3: Test it

```bash cURL theme={null}
TOKEN=$(curl -s -X POST "https://api.coverbase.app/v1/oauth/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" | jq -r .access_token)

curl -H "Authorization: Bearer $TOKEN" https://api.coverbase.app/v1/utils/authtest
```

`{"msg": "Auth successful"}` means the token works. Request a new token when `expires_in` runs out. This grant has no refresh token. Reuse a token until it expires: a client holds at most 50 live tokens, and requesting a 51st revokes its oldest.

## Revoke

On the **API keys** page, click **Revoke** on the client and confirm **Revoke client**. The client can no longer get tokens, and its current tokens stop working. A server that cached a token can keep accepting it for a few seconds. **Last Token** shows when each client last asked for a token, which helps find clients nobody uses.

## Troubleshooting

| What you see | Cause | Fix |
| - | - | - |
| No **OAuth Clients** section on the **API keys** page | The third-party lifecycle features are not on for your organization, or you are not an admin. | Ask your Coverbase representative, or an admin. |
| `401 invalid_client` | Wrong client ID or secret, or the client is revoked. | Check both values. Create a new client if the secret is lost. |
| `400 unsupported_grant_type` | `grant_type` is missing, or the body was sent as JSON. | Send `grant_type=client_credentials`, form-encoded. |
| `400 invalid_scope` | The token request asks for a scope the client was not granted. | Request fewer scopes, or create a client with the scope. |
| `403 insufficient_scope` on a call | The token lacks a scope the endpoint needs. | Request the scope when getting the token, if the client holds it. |
| `403 ip_not_allowed` | Your platform's egress IP is outside the allowlist. | Add it to the [IP allowlist](/conventions#api-ip-allowlist). |

## Related

<CardGroup cols={2}>
  <Card title="OAuth API" icon="code" href="/api-reference/oauth">
    The token endpoint and client management.
  </Card>

  <Card title="API conventions" icon="ruler-combined" href="/conventions">
    Authentication, scopes, errors and pagination.
  </Card>

  <Card title="Integration platforms" icon="diagram-project" href="/integrations/guides/integration-platforms">
    Workato, MuleSoft and Boomi.
  </Card>

  <Card title="Integration credentials and signing" icon="key" href="/security/integration-credentials#oauth-client-secrets">
    How client secrets are stored.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.