fix(serve): bootstrap session tokens for instance-token-authenticated front-ends - #116
Merged
Merged
Conversation
… front-ends Sessions created by one front-end (e.g. bodek, or the WebUI in another browser profile) could not be loaded by another: every new session gets a 256-bit AuthToken that only reaches the creating client, and the token bootstrap only covered legacy sessions with no token at all - so GET /api/sessions/<id> returned 401 and the WebUI showed "Failed to load session". The GET handler now also bootstraps the session token when the caller proves knowledge of the per-instance CSRF token by presenting it in the X-Odek-Ws-Token header (constant-time compared). Header presentation is a knowledge proof a cross-origin page cannot forge: a DNS-rebinding page holds only the ambient SameSite=Strict cookie and can neither read the token value nor set the custom header (CORS preflight, which odek does not answer). Cookie-only callers therefore still get 401 on token-carrying sessions, while the operator's legitimate front-ends - which always send the header via apiHeaders - can load each other's sessions. The rebinding damage boundary is unchanged; DELETE/POST (rename) flows inherit the fix through the client's existing ensureSessionToken GET bootstrap. Regression tests cover: bootstrap with a valid instance header (200 + X-Session-Token), no bootstrap with a wrong instance header (401), and no bootstrap for cookie-only callers (401). Docs updated (SECURITY.md section 24, AGENTS.md).
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
odek | c1b72ac | Commit Preview URL Branch Preview URL |
Jul 26 2026, 04:45 PM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(serve): bootstrap session tokens for instance-token-authenticated front-ends
Sessions created by one front-end (e.g. bodek, or the WebUI in another
browser profile) could not be loaded by another: every new session gets a
256-bit AuthToken that only reaches the creating client, and the token
bootstrap only covered legacy sessions with no token at all - so
GET /api/sessions/ returned 401 and the WebUI showed "Failed to load
session".
The GET handler now also bootstraps the session token when the caller
proves knowledge of the per-instance CSRF token by presenting it in the
X-Odek-Ws-Token header (constant-time compared). Header presentation is a
knowledge proof a cross-origin page cannot forge: a DNS-rebinding page
holds only the ambient SameSite=Strict cookie and can neither read the
token value nor set the custom header (CORS preflight, which odek does
not answer). Cookie-only callers therefore still get 401 on
token-carrying sessions, while the operator's legitimate front-ends -
which always send the header via apiHeaders - can load each other's
sessions. The rebinding damage boundary is unchanged; DELETE/POST
(rename) flows inherit the fix through the client's existing
ensureSessionToken GET bootstrap.
Regression tests cover: bootstrap with a valid instance header (200 +
X-Session-Token), no bootstrap with a wrong instance header (401), and no
bootstrap for cookie-only callers (401). Docs updated (SECURITY.md
section 24, AGENTS.md).