Sidecar: auth token for the website-facing API

config.rs loads all runtime settings from an external sidecar.toml (path via
$UOLINK_CONFIG), with env-var overrides (UOLINK_WEB_TOKEN, UOLINK_WEB_BIND,
UOLINK_SHARD_BIND, UOLINK_DB_PATH). Nothing is compiled into the binary. On first
run the file is generated with a random 24-byte auth token, so the sidecar is
secured out of the box and the operator just copies the token to the website.

An axum middleware rejects any request to a non-/health route that does not
present the token, as Authorization: Bearer, X-Api-Key, or ?token= (the last so
browser WebSocket clients, which cannot set handshake headers, can authenticate).
The comparison is constant-time. An empty token disables auth and is only
tolerated on a loopback bind; binding to 0.0.0.0 with no token logs a warning.

Verified: /health open (200); /history 401 without a token, 401 with a wrong one,
200 with the right one via either Bearer or X-Api-Key; an authed shard query
falls through to 503 when no shard is connected; WS rejected (401) with a bad
?token= and upgraded (101) with the right one.

sidecar.toml is gitignored (holds the secret); sidecar.toml.example is committed
as the reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 16:56:55 -05:00
parent 946ba7027b
commit c4de5fa8ad
9 changed files with 469 additions and 13 deletions

View File

@@ -13,6 +13,8 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
anyhow = "1"
axum = { version = "0.7", features = ["ws"] }
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite"] }
toml = "0.8"
getrandom = "0.2"
[profile.release]
opt-level = 2