Shared-secret gate for the web UI.
The web UI hands whoever reaches it an arbitrary-command agent console
(client-chosen cwd, bash/write tools, a real interactive terminal), so
exposure beyond loopback must be authenticated. mix athena.web decides
the policy: bound to loopback there is no token and this module is a
no-op; bound wider (--lan / --host) a token is required and stored
under config :ex_athena, ExAthena.Web.Auth, token: ....
Enforcement happens twice, because plugs do not run on the LiveView websocket:
call/2(plug, HTTP entry) — accepts?token=<secret>once, stamps it into the session, and redirects to the same path without the query token; otherwise requires an already-stamped session. Everything else is a 403.on_mount/4(websocket entry) — re-verifies the session token on every LiveView mount. This is the gate that actually protects the high-privilege events; a halted mount redirects to/, where the plug renders the 403.
Tokens are compared with Plug.Crypto.secure_compare/2, and the session
stores the token itself, so restarting the server with a fresh secret
invalidates previously authorized browsers.
Summary
Functions
LiveView on_mount hook — verifies the session token on the websocket,
where plugs never run.
The token required for access, or nil when the UI is open (loopback).
Functions
LiveView on_mount hook — verifies the session token on the websocket,
where plugs never run.
@spec required_token() :: String.t() | nil
The token required for access, or nil when the UI is open (loopback).