> For the complete documentation index, see [llms.txt](https://developer.abacum.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.abacum.ai/essentials/authenticate.md).

# Authenticate

Exchange your credentials for an access token.

Abacum uses the OAuth 2.0 client credentials flow. Send your client ID and client secret to the token endpoint. Then send the access token that you get back with every other call.

## Request a token

{% tabs %}
{% tab title="curl" %}
{% code collapsedlinecount="10" %}

```bash
curl -X POST https://api.abacum.io/server-authentication/oauth2/token/ \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code collapsedlinecount="10" %}

```python
import requests

response = requests.post(
    "https://api.abacum.io/server-authentication/oauth2/token/",
    data={
        "grant_type": "client_credentials",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
    },
)
response.raise_for_status()
access_token = response.json()["access_token"]
```

{% endcode %}
{% endtab %}
{% endtabs %}

The response holds the `access_token`. It also holds `expires_in`, the lifetime of the token in seconds.

## Use the token

Send the token in the `Authorization` header of every request:

{% code collapsedlinecount="10" %}

```
Authorization: Bearer YOUR_ACCESS_TOKEN
```

{% endcode %}

## Token lifetime

An access token lasts 7 days (604,800 seconds). Your client ID and client secret do not expire.

Do not request a new token for every call. Store the token and use it again. Request a new token before the current one expires. Use the same token request to do this.

{% hint style="info" %}
A missing, malformed or expired token returns `403`. Request a new token.
{% endhint %}

## Scope

The token response has a `scope` field with the value `read`. Access comes from the role of the user who owns the credentials. You can ignore the `scope` field in the response. You do not send a scope in the token request.

A token carries the permissions of the user who created the credentials. It is not limited to reading. It can change data when the role of that user allows it. See [Access and permissions](/essentials/concepts/access-and-permissions.md). If you give a token to an AI agent, see [Use the docs with AI tools](/resources/use-the-docs-with-ai-tools.md).

## Reference

## Generate access token

> Exchange your \`client\_id\` and \`client\_secret\` for an OAuth2 bearer token that\
> lasts 7 days, using the Client Credentials grant. Include the token as \`Authorization: Bearer \<access\_token>\`\
> on all API requests. You can also send the client ID and secret as HTTP Basic authentication instead of in the body.\
> \
> \*\*Example request\*\*\
> \`\`\`\
> curl -X POST <https://api.abacum.io/server-authentication/oauth2/token/> \\\
> &#x20; -H "Content-Type: application/x-www-form-urlencoded" \\\
> &#x20; -d "grant\_type=client\_credentials\&client\_id=\<client\_id>\&client\_secret=\<client\_secret>"\
> \`\`\`<br>

````json
{"openapi":"3.0.0","info":{"title":"Abacum public API","version":"1.0.0"},"tags":[{"name":"Authentication","description":"Exchange your client ID and client secret for an access token."}],"servers":[{"url":"https://api.abacum.io","description":"Prod environment"}],"security":[],"paths":{"/server-authentication/oauth2/token/":{"post":{"summary":"Generate access token","description":"Exchange your `client_id` and `client_secret` for an OAuth2 bearer token that\nlasts 7 days, using the Client Credentials grant. Include the token as `Authorization: Bearer <access_token>`\non all API requests. You can also send the client ID and secret as HTTP Basic authentication instead of in the body.\n\n**Example request**\n```\ncurl -X POST https://api.abacum.io/server-authentication/oauth2/token/ \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>\"\n```\n","operationId":"generateToken","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type","client_id","client_secret"],"properties":{"grant_type":{"type":"string","enum":["client_credentials"],"description":"Must be `client_credentials`."},"client_id":{"type":"string","description":"The client ID issued for your OAuth2 application."},"client_secret":{"type":"string","description":"The client secret issued for your OAuth2 application."}}}}}},"responses":{"200":{"description":"Access token issued successfully.","content":{"application/json":{"schema":{"type":"object","required":["access_token","token_type","expires_in","scope"],"properties":{"access_token":{"type":"string","description":"Bearer token to include in the `Authorization` header."},"token_type":{"type":"string"},"expires_in":{"type":"integer","description":"Token lifetime in seconds."},"scope":{"type":"string"}}}}}},"400":{"description":"Invalid request - a missing or incorrect parameter, or a `grant_type` other than `client_credentials`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2Error"}}}},"401":{"description":"Invalid client credentials.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuth2Error"}}}}}}}},"components":{"schemas":{"OAuth2Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}}}
````
