Skip to main content

SessionAuthority

Struct SessionAuthority 

Source
pub struct SessionAuthority<M, R, U, W> { /* private fields */ }
Expand description

Origin facade: everything that can create or destroy sessions.

Holds the four origin-tier capabilities — a TokenMinter, a RefreshStore, a UserStore, and a RevocationWriter — plus a SessionPolicy. Generic (not dyn) so the assembled capability set is visible in the type; a consumer wires concrete impls (e.g. PasetoV4SecretMinter + Yubaba-backed stores).

Implementations§

Source§

impl<M, R, U, W> SessionAuthority<M, R, U, W>

Source

pub fn new(minter: M, refresh: R, users: U, revoke: W) -> Self

Assemble an authority with the default policy.

Source

pub fn with_policy(self, policy: SessionPolicy) -> Self

Override the TTL policy.

Source

pub fn with_standing_binder(self, binder: StandingBinder) -> Self

Mint standing node bindings with binder (R732-F5). Required before establish_bound / rotate_bound will serve a DeviceBinding::LanPair session.

Source

pub fn policy(&self) -> &SessionPolicy

Source

pub fn users(&self) -> &U

The held UserStore, for device-management reads (list_devices).

Source

pub async fn establish( &self, sub: UserId, device: DeviceId, binding: DeviceBinding, now: i64, ) -> Result<NewSession, Error>

Establish a fresh session: mint a short-TTL access token (with a fresh jti) and start a homed refresh chain for (sub, device).

Source

pub async fn establish_bound( &self, sub: UserId, device: DeviceId, binding: DeviceBinding, peer_key: PeerKey, now: i64, ) -> Result<NewSession, Error>

Establish a session whose access token is bound to peer_key — the mint half of R515.

Identical to establish except the minted claims carry Claims::peer_key, so a verifier that has already authenticated the connecting peer under that key can prove token holder == connecting peer (see EdgeVerifier::verify_bound_at). A token stolen from this client is then useless to a thief connecting under their own key.

cheers does not establish that the caller possesses peer_key — that proof belongs to the enrollment ceremony in the consuming service (the app proves possession of the key, presents its existing session, and then calls this). cheers’s own HTTP ceremonies can’t do it: a browser passkey or magic-link sign-in has no node key at all.

The refresh chain is unchanged, and deliberately does not record the key: like binding, the peer key is a fact about this access token, not about the chain — so rotate_bound takes it from the caller again.

LanPair (R732-F5). For DeviceBinding::LanPair the session also carries a standing binding — user to node key, no expiry, ended only by revocation or a newer binding for device — minted by the standing binder. Without one this refuses with Error::NoStandingBinder before anything is written.

Source

pub async fn rotate<B: BindingResolver + ?Sized>( &self, presented_refresh: &str, binding: &B, now: i64, ) -> Result<NewSession, Error>

Rotate presented_refresh → fresh access token + successor refresh token. Replay detection / chain revocation are the rotator’s (see RefreshRotator::rotate).

The binding comes from the caller’s BindingResolver because the refresh record doesn’t carry it — guide by omission, the refresh chain is about which session, not how it authenticated. A caller that already knows the binding passes &DeviceBinding::… (a fixed binding is a resolver); a generic door that only holds the refresh token passes the product’s session rows, keyed by the chain’s (user, device).

Ordering (R730). The token is checked, then the binding resolved, then the token spent and the access token minted. A resolver that knows no binding yields RefreshError::Unbound with the token still unspent and the chain untouched — never a guessed or unbound mint, and never a half-rotated chain whose successor the client was not handed. Replay detection still runs first, so a replayed token revokes its chain whether or not a binding exists.

Source

pub async fn rotate_bound<B: BindingResolver + ?Sized>( &self, presented_refresh: &str, binding: &B, peer_key: PeerKey, now: i64, ) -> Result<NewSession, Error>

Rotate into a fresh access token that is bound to peer_key (R515).

The peer key is supplied by the caller for the same reason binding is: the refresh record is about which session, not about how this particular access token is being presented. A node re-binds on every rotation, which is what keeps the binding honest if the node key changes — for a DeviceBinding::LanPair session that includes a fresh standing binding whose higher sequence supersedes the previous one (see establish_bound).

Source

pub async fn revoke_session(&self, jti: &str, exp: i64) -> Result<(), Error>

Revoke a single access token by its jti — the immediate, edge-visible kill (within the propagation window bounded by the access TTL). exp is the token’s own expiry: past it the entry lapses and gc drops it.

Source

pub async fn revoke_standing_binding(&self, jti: &str) -> Result<(), Error>

Revoke one standing node binding by its jti. A standing binding has no exp, so the entry never lapses.

Source

pub async fn revoke_device( &self, user_id: &UserId, device_id: &DeviceId, now: i64, ) -> Result<(), Error>

Records device-level revocation intent via the UserStore, and Revoked::Device in the revocation set — the entry that ends a standing node binding for this device at offline replicas (R732-F6).

The entry’s at_seq is the device’s next binding sequence, consumed from the standing binder at now: every binding minted before it is masked, and re-enrolling the device later mints above it and is admitted (R732-T7). With no binder configured this authority has minted no standing bindings, so there is nothing for a device entry to end and none is recorded. Blocking new sessions also means revoking that device’s refresh chains via the RefreshStore; killing an in-flight access token is revoke_session. The product owns the device→chain index that drives the first, so this facade exposes the store call and the per-jti kill, not a magic “log out everywhere”.

Auto Trait Implementations§

§

impl<M, R, U, W> !RefUnwindSafe for SessionAuthority<M, R, U, W>

§

impl<M, R, U, W> !UnwindSafe for SessionAuthority<M, R, U, W>

§

impl<M, R, U, W> Freeze for SessionAuthority<M, R, U, W>
where M: Freeze, R: Freeze, U: Freeze, W: Freeze,

§

impl<M, R, U, W> Send for SessionAuthority<M, R, U, W>
where M: Send, R: Send, U: Send, W: Send,

§

impl<M, R, U, W> Sync for SessionAuthority<M, R, U, W>
where M: Sync, R: Sync, U: Sync, W: Sync,

§

impl<M, R, U, W> Unpin for SessionAuthority<M, R, U, W>
where M: Unpin, R: Unpin, U: Unpin, W: Unpin,

§

impl<M, R, U, W> UnsafeUnpin for SessionAuthority<M, R, U, W>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more