lilydocs
HTTP APIWebSocketConsumer
Connections3 min read

Identity refresh and expiry

Verify new credentials, apply revision-checked identity replacement, and manage expired connections.

A long-lived connection's credentials can be refreshed without closing it. Lily applies the update conditionally using a revision; credential verification still belongs to your application's verifier.

Read the revision first#

Read the revision from context.identity_snapshot() before starting async verification. After the verifier validates the new credentials, publish the replacement identity with that revision:

identity_refresh.rs
use lilyrs::websocket::{AuthenticatedWebSocketIdentity, Principal, WebSocketContext,
    WebSocketIdentityUpdateOutcome};

async fn publish_verified_identity(
    context: &WebSocketContext,
    observed: lilyrs::websocket::WebSocketIdentityRevision,
    verified_principal: Principal,
    expiry: tokio::time::Instant,
) -> Result<WebSocketIdentityUpdateOutcome, Box<dyn std::error::Error>> {
    let replacement = AuthenticatedWebSocketIdentity::try_new(verified_principal)?
        .expires_at(expiry);
    Ok(context.reauthenticate(observed, replacement).await?)
}

Download the complete example.

The helper does not verify tokens. verified_principal and expiry are results of real verification. Reading the revision after verification can allow an old verification result to overwrite a newer identity published in between.

Handle the update result#

Result Meaning Application decision
Updated(new_revision) Replacement was published Use the new revision
Stale(current_revision) A newer identity was published in between Do not force the old result through automatic retries
AlreadyClosing The connection is closing Do not start new session work

Explicitly define your refresh action and decide how to carry credentials. Lily does not generate a refresh endpoint or an OIDC flow. Use the ACK contract to notify the client of a successful update.

Message snapshots and local data#

Each message snapshots the Principal once. Middleware, guards, and the action processing that message see the same identity; a successful refresh affects subsequent messages. The original handshake Principal remains the initial identity in the audit view.

This API does not rewrite connection locals. Evaluate renewable permissions through current identity and an application service instead of embedding them in an immutable tenant local. Principal targets use the current index.

Expiry#

expires_at accepts a tokio::time::Instant, not an epoch timestamp. A deadline in the past is rejected. When expiry arrives, if that revision is still authoritative, principal-index membership is removed, new message/broadcast admission stops, and closure with 1008, lily.v2.identity_expired is attempted.

An old revision's timer cannot expire the new identity. Without identity middleware, this expiry and principal-index lifecycle is not installed either. Application session-revocation or refresh services separately check state in their own data source.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code