Skip to main content

Module session_token

Module session_token 

Source
Expand description

zackees/soldr#2360/#2363 — composite broker/daemon session token authority. Wired into hello_handler via HelloHandler::with_session_token_authority — see the module docs. Composite broker/daemon session token authority (zackees/soldr#2360, #2361 Phase 1, #2363).

STATUS: wired into crate::broker::server::hello_handler::HelloHandler via with_session_token_authority — opt-in, dormant unless a caller configures it. See “Not done yet” below for what’s still open.

§What this is — a cooperative invalidation signal, NOT authentication

This is a liveness/generation notification scheme for a cooperative client inside one trust domain (all roles run as the same user on the same machine). It is not a security boundary and does not authenticate anyone.

Every client session carries a composite token broker_token ‖ daemon_token: the first half minted once by the broker at its own startup, the second minted by the specific daemon the client is talking to. The halves are generation markers — “the broker/daemon incarnation you established this session against”. When a presented token stops validating, that tells the client its session has terminated or the broker/daemon got forcefully cycled since its last message: the session is invalid, and the client should report the error (the cancelled-because-stopped message class, soldr#2363), unwind, and exit 1 — never retry against the new incarnation as if nothing happened. Two-level invalidation falls out of the split for free:

  • Rotating the broker half signals every session across every daemon at once (broker restart, or a live rotation e.g. after the spawn-storm guard trips).
  • Invalidating one daemon’s half signals only that daemon’s sessions; sessions against other daemons are unaffected.

The halves come from OS randomness only so that incarnations are globally unique — a restarted broker or daemon can never accidentally validate a stale token minted by its predecessor, the way a counter or timestamp could collide. The bytes are not secrets guarding anything, which is also why the plain != comparison (mirroring crate::broker::server::handoff::HandoffToken) is fine here: constant-time comparison defends secrets against guessing oracles, and there is no secret and nothing to guess for.

There is deliberately no TTL on these tokens. A session may go silent for arbitrarily long (e.g. a link phase with no daemon traffic) and remain valid; invalidation is communicated lazily, just in time, on the next communication intent — the client learns its session died at the exact moment it next tries to use it, which is the only moment it matters.

This module is the authority that mints, rotates, and validates both halves. It deliberately knows nothing about the wire (Hello.auth_token, already reserved on the v2-reuses-v1-framing Hello message — see broker_v1_envelope.proto) or about HelloHandler / RegisteredBackend — see “Not done yet”.

§Not done yet (left for a follow-up slice)

  • daemon_id is resolved as hello.service_name — the same key RegisteredBackend already uses — rather than a new field. Refused uses ERROR_PEER_REJECTED for every crate::broker::server::session_token::SessionTokenRejection kind. Both settled in the HelloHandler wiring.
  • Where the authority instance itself lives (per-broker-process singleton state) and how register_daemon/invalidate_daemon are threaded into the daemon spawn/exit lifecycle — that’s soldr#2361 Phase 2 (spawn-chain inversion), which is what will actually call with_session_token_authority and stop this from being dormant.
  • Persistence-boundary invariant from soldr#2363’s testing invariants (“no token material is ever written under a daemon cache root”) — this module is pure in-memory today, so that invariant holds trivially for it, but the caller that eventually persists broker-side session state must uphold it too.

Structs§

SessionTokenAuthority
Mints, rotates, and validates the composite broker_token ‖ daemon_token pair described in the module docs.
TokenHalf
One 128-bit half of a composite session token. Used for both the broker-minted half and each daemon-minted half — the two are typed identically; which is which is a matter of which map an instance is looked up in, not a type-level distinction.

Enums§

SessionTokenError
Errors raised while minting session-token halves.
SessionTokenRejection
Why a presented composite token failed validation.

Constants§

SESSION_TOKEN_HALF_BYTES
Number of bytes in one half of the composite token (128 bits), matching super::handoff::HandoffToken’s existing size for consistency.
SESSION_TOKEN_TOTAL_BYTES
Total presented-token length: broker half + daemon half.

Functions§

compose_presented_token
Concatenate a broker half and a daemon half into one presented-token byte vector, matching what SessionTokenAuthority::validate expects. A convenience for a client-side caller assembling Hello.auth_token.

Type Aliases§

DaemonId
Opaque identifier for one daemon’s token slot. Deliberately a plain String rather than reusing ServiceDefinition’s type, since how a daemon identity maps to a registered backend is one of the open wiring questions above — this keeps the authority decoupled from that decision until it’s made.