.. _ADR-09: ADR-09: API keys for REST automation ==================================== Context ------- Authentication is delegated to an OIDC provider (:ref:`ADR-07`), which works well for interactive users: the browser-based SSO flow establishes a session cookie. Automation cannot follow that flow. A CI pipeline or a script has no browser to complete an authorization-code exchange, yet it still needs to call the :ref:`REST API` — to generate a document, commit it, or download a bucket. A credential was needed that a non-interactive client can put in a request header. Decision -------- TINO issues **static API keys** — long-lived bearer tokens for programmatic access to the REST API. - Keys are generated by administrators (via the web UI or the API). - Keys are presented as ``Authorization: Bearer tino_…``. - Each key carries an explicit **per-bucket access map** (bucket slug → role). - Keys are stored in a single ``api_keys.yml`` file in the data directory, consistent with the filesystem-only state model (:ref:`ADR-02`). - Only a hash of the token is stored and the raw token is shown once at creation and never again. Consequences ------------ Positive ~~~~~~~~ - | **Automation without a browser** | CI pipelines and scripts authenticate with a single header, no interactive login required. - | **No database** | Keys live in ``api_keys.yml`` alongside the rest of TINO's state, backed up and inspected with the same filesystem tools (:ref:`ADR-02`). - | **Explicit scoping** | A key grants exactly the per-bucket roles it was given — least privilege by construction, and revocation is deleting one entry. - | **Hashed at rest** | Only token hashes are stored, so a leaked ``api_keys.yml`` exposes no usable credentials. Negative ~~~~~~~~ - | **Long-lived secrets** | A key stays valid until explicitly revoked — there is no automatic expiry. Leaked keys must be revoked by hand, which argues for narrow scoping. - | **Manual lifecycle** | Creating, rotating, and revoking keys is an administrator's responsibility rather than something the identity provider manages. - | **Snapshotted access** | A key's bucket roles are fixed at creation and do not follow OIDC group changes. | Access must be updated on the key itself.