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 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.

Source

pub async fn rotate( &self, presented_refresh: &str, binding: DeviceBinding, 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 is supplied by the caller because the refresh record doesn’t carry it — guide by omission, the refresh chain is about which session, not how it authenticated.

Source

pub async fn rotate_bound( &self, presented_refresh: &str, binding: DeviceBinding, 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.

Source

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

Revoke a single access token by its jti — the immediate, edge-visible kill (within the propagation window bounded by the access TTL).

Source

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

Records device-level revocation intent via the UserStore. 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> Freeze for SessionAuthority<M, R, U, W>
where M: Freeze, R: Freeze, U: Freeze, W: Freeze,

§

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

§

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>

§

impl<M, R, U, W> UnwindSafe 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, 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.