# Server-to-server (S2S)

In addition to interactive authentication (Login form, OAuth2/OIDC, LDAP), ODD Platform supports **server-to-server (S2S) API-key authentication** (also called **machine-to-machine (M2M) tokens**) for programmatic clients that cannot go through an interactive login — CI/CD jobs, automation scripts, scheduled ingestion pipelines, and any other non-human callers of the Platform API.

## How it works

* A single long-lived token is configured on the platform via `auth.s2s.token`.
* Clients present the token in the `X-API-Key` HTTP header on every request.
* Requests carrying a valid token run with the built-in `ADMIN` user and ADMIN role, so they can call any endpoint that admins can call — including the ingestion API, management APIs, and entity mutations.
* S2S runs **alongside** the configured interactive auth mechanism, not instead of it. If a request has no `X-API-Key` header (or the value doesn't match), the filter falls through and the normal auth chain (Login form / OAuth2 / LDAP) handles the request. This means enabling S2S does not affect the user login flow.

{% hint style="info" %}
S2S is available when `auth.type` is `LOGIN_FORM`, `OAUTH2`, or `LDAP`. With `auth.type: DISABLED`, the platform is already open and S2S is not needed.
{% endhint %}

## Configuration

| Property           | Default   | Description                                                                                                                                                                                                                      |
| ------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auth.s2s.enabled` | `false`   | Turns the S2S filter on. When `true`, `auth.s2s.token` must be set — the platform refuses to start if the token is missing.                                                                                                      |
| `auth.s2s.token`   | *(unset)* | The shared API key. Any request presenting this value in the `X-API-Key` header is authenticated as the built-in `ADMIN` user. Treat this as a high-privilege secret and store it in a secrets manager, not in plaintext config. |

{% tabs %}
{% tab title="YAML" %}

```yaml
auth:
    type: OAUTH2          # or LOGIN_FORM / LDAP
    s2s:
        enabled: true
        token: {long_random_token}
```

{% endtab %}

{% tab title="Environment variables" %}

```
AUTH_TYPE=OAUTH2
AUTH_S2S_ENABLED=true
AUTH_S2S_TOKEN={long_random_token}
```

{% endtab %}
{% endtabs %}

## Using the token

Send the token in the `X-API-Key` header on every request:

```bash
curl -X POST https://{platform_host}/ingestion/entities \
     -H "X-API-Key: {long_random_token}" \
     -H "Content-Type: application/json" \
     -d @payload.json
```

The same header works for any other Platform API endpoint — for example, listing data sources:

```bash
curl https://{platform_host}/api/datasources \
     -H "X-API-Key: {long_random_token}"
```

## Security considerations

* The token is a **single static string** compared for equality — it is not rotated, expired, or scoped. Rotating it requires restarting the platform with a new `auth.s2s.token` value.
* Any client that holds the token gets full ADMIN access to the Platform API. Prefer to scope its distribution narrowly: one token per trusted caller tier, not one token shared across unrelated systems.
* Transport the token only over HTTPS. If the platform is exposed over plain HTTP, anyone on the network path can capture and replay the token.
* If you only need to authenticate the ingestion pipeline (collectors / push adapters), consider combining S2S with `auth.ingestion.filter.enabled: true` so the ingestion endpoints remain protected even when S2S is not enabled — see [Enable security](/configuration-and-deployment/enable-security.md) for the details.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.opendatadiscovery.org/configuration-and-deployment/enable-security/authentication/s2s.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
