Authenticate the HTTP caller, which sessions cannot land before #414

Closed
opened 2026-08-13 12:23:43 +00:00 by coilyco-ops · 0 comments
Member

Slice of #165, which Kai approved on 2026-08-12. Identity only. Sessions are the other half and cannot come first.

Scope

SIRENS_ECHO_HTTP_TOKEN supplies a token. A request presenting Authorization: Bearer <token> is trusted; everything else is not. Constant-time comparison.

Unset trusts nobody, which is exactly what this endpoint did before the token existed, so landing this changes nothing until a deployment decides otherwise.

The trap this deliberately avoids

X-Sirens-Caller already exists, is self-asserted, and is used as a rate-limit key. It is a header named like an identity, carrying a caller-supplied name, already flowing into the turn's requester.

The smallest possible version of "add identity" is to trust it, and that step is treating an unauthenticated string as a principal. It would pass every test anyone would think to write, because the plumbing works and the value arrives where expected. So the trusted input is a different input and the self-asserted one keeps its old meaning. A test asserts it grants no trust and still partitions the rate limit.

Why identity before sessions

A session is a handle to retained conversation. An endpoint accepting a session id from an unauthenticated caller and returning that session's history discloses conversations to whoever guesses an id. history_count: 0 is not merely a missing feature — it is why this endpoint is currently safe without authentication.

What trust does today: nothing

Beyond a span attribute recording whether the caller authenticated. The value of this change is that the distinction exists and is recorded; every consumer of it is a separate decision.

The prompt still says an HTTP caller is not the principal. Making that conditional means rebuilding the system prompt per request, since it is built once at startup — a cost and a design question, not a line of code, and it deserves its own issue.

Acceptance

  • No configured token trusts nobody, whatever the request carries.
  • The configured token is trusted; a prefix, a superstring, a wrong scheme, and a missing scheme are not.
  • X-Sirens-Caller grants no trust and still partitions the rate limit.
**Slice of** https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/165, which Kai approved on 2026-08-12. Identity only. Sessions are the other half and cannot come first. ## Scope `SIRENS_ECHO_HTTP_TOKEN` supplies a token. A request presenting `Authorization: Bearer <token>` is trusted; everything else is not. Constant-time comparison. **Unset trusts nobody**, which is exactly what this endpoint did before the token existed, so landing this changes nothing until a deployment decides otherwise. ## The trap this deliberately avoids `X-Sirens-Caller` already exists, is self-asserted, and is used as a rate-limit key. It is a header named like an identity, carrying a caller-supplied name, already flowing into the turn's requester. **The smallest possible version of "add identity" is to trust it**, and that step is treating an unauthenticated string as a principal. It would pass every test anyone would think to write, because the plumbing works and the value arrives where expected. So the trusted input is a different input and the self-asserted one keeps its old meaning. A test asserts it grants no trust and still partitions the rate limit. ## Why identity before sessions A session is a handle to retained conversation. An endpoint accepting a session id from an unauthenticated caller and returning that session's history discloses conversations to whoever guesses an id. `history_count: 0` is not merely a missing feature — it is why this endpoint is currently safe without authentication. ## What trust does today: nothing Beyond a span attribute recording whether the caller authenticated. The value of this change is that the distinction exists and is recorded; every consumer of it is a separate decision. The prompt still says an HTTP caller is not the principal. Making that conditional means rebuilding the system prompt per request, since it is built once at startup — a cost and a design question, not a line of code, and it deserves its own issue. ## Acceptance - No configured token trusts nobody, whatever the request carries. - The configured token is trusted; a prefix, a superstring, a wrong scheme, and a missing scheme are not. - `X-Sirens-Caller` grants no trust and still partitions the rate limit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo#414
No description provided.