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

# Authentication

> Authenticate API requests using a Service Token obtained via the OAuth2 Client Credentials flow.

# Authentication

All API requests are authenticated using a **Service Token** — a short-lived Bearer token obtained via the OAuth2 Client Credentials grant. This is a machine-to-machine flow: no human login is involved.

***

## How it works

Your integration holds a `client_id` and `client_secret` (provided by your DokStamp account manager). Exchange them for an access token, then include that token in every API request.

```
client_id + client_secret
        │
        ▼
POST /oauth/token
        │
        ▼
access_token (valid 12h)
        │
        ▼
Authorization: Bearer {access_token}
```

***

## 1. Obtain a token

```http theme={null}
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.dokstamp.com/oauth/token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch('https://api.dokstamp.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.DOKSTAMP_CLIENT_ID,
      client_secret: process.env.DOKSTAMP_CLIENT_SECRET,
    }),
  });
  const { access_token, expires_in } = await res.json();
  ```

  ```php PHP theme={null}
  $response = Http::asForm()->post('https://api.dokstamp.com/oauth/token', [
      'grant_type'    => 'client_credentials',
      'client_id'     => env('DOKSTAMP_CLIENT_ID'),
      'client_secret' => env('DOKSTAMP_CLIENT_SECRET'),
  ]);
  $token = $response->json('access_token');
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "token_type": "Bearer",
  "expires_in": 43200,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
}
```

| Field          | Description                                              |
| -------------- | -------------------------------------------------------- |
| `access_token` | Include in every API request via `Authorization: Bearer` |
| `expires_in`   | Validity in seconds — **43 200 = 12 hours**              |

***

## 2. Use the token

Include the token in every subsequent request:

```http theme={null}
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...
Accept: application/json
X-Tenant: your-tenant-identifier
```

***

## 3. Token renewal

Tokens expire after **12 hours**. There is no refresh token — request a new one with your credentials when needed. Recommended pattern: cache the token and renew proactively \~60 seconds before expiry.

```javascript theme={null}
let token = null;
let expiresAt = null;

async function getToken() {
  if (token && Date.now() < expiresAt - 60_000) return token;

  const res = await fetch('https://api.dokstamp.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.DOKSTAMP_CLIENT_ID,
      client_secret: process.env.DOKSTAMP_CLIENT_SECRET,
    }),
  });

  const data = await res.json();
  token = data.access_token;
  expiresAt = Date.now() + data.expires_in * 1000;
  return token;
}
```

***

## Public endpoints

These endpoints do **not** require authentication:

| Endpoint                     | Purpose                    |
| ---------------------------- | -------------------------- |
| `POST /oauth/token`          | Obtain a service token     |
| `GET /files/{uuid}/download` | Download a signed document |

<Note>
  Store `client_id` and `client_secret` in environment variables or a secrets manager. Never commit them to source code.
</Note>
