ADR-09: API keys for REST automationยถ
Contextยถ
Authentication is delegated to an OIDC provider (ADR-07: OIDC for authentication), 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 ๐ 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.ymlfile in the data directory, consistent with the filesystem-only state model (ADR-02: No database).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 browserCI pipelines and scripts authenticate with a single header, no interactive login required.
- No databaseKeys live in
api_keys.ymlalongside the rest of TINOโs state, backed up and inspected with the same filesystem tools (ADR-02: No database). - Explicit scopingA key grants exactly the per-bucket roles it was given โ least privilege by construction, and revocation is deleting one entry.
- Hashed at restOnly token hashes are stored, so a leaked
api_keys.ymlexposes no usable credentials.
Negativeยถ
- Long-lived secretsA key stays valid until explicitly revoked โ there is no automatic expiry. Leaked keys must be revoked by hand, which argues for narrow scoping.
- Manual lifecycleCreating, rotating, and revoking keys is an administratorโs responsibility rather than something the identity provider manages.
- Snapshotted accessA keyโs bucket roles are fixed at creation and do not follow OIDC group changes.Access must be updated on the key itself.