Poem
The Poem adapter nests the auth API as a single Endpoint and provides CurrentSession and OptionalSession extractors. Enable the poem feature and add poem to your application:
alibi = { version = "0.1.1", features = ["poem"] }poem = "3.1"Mount the endpoint and protect a route
Section titled “Mount the endpoint and protect a route”Build the auth instance with your SQLx or SeaORM store as usual, then nest poem_endpoint() at the configured base path and install the instance as shared data for the extractors:
use crate::auth_schema::AppAuthSchema;use alibi::BetterAuth;use alibi::integrations::poem::{CurrentSession, PoemIntegration};use alibi::prelude::AuthUser;use poem::{Endpoint, EndpointExt, Route, get, handler};use std::sync::Arc;
#[handler]async fn profile(session: CurrentSession<AppAuthSchema>) -> String { format!("Hello, {}", session.user.id())}
fn app(auth: Arc<BetterAuth<AppAuthSchema>>) -> impl Endpoint { Route::new() .nest("/api/auth", auth.clone().poem_endpoint()) .at("/profile", get(profile)) .data(auth)}Serve it with Poem’s server:
use crate::auth_schema::AppAuthSchema;use alibi::BetterAuth;use alibi::integrations::poem::PoemIntegration;use poem::{EndpointExt, Route, Server, listener::TcpListener};use std::sync::Arc;
async fn serve(auth: Arc<BetterAuth<AppAuthSchema>>) -> std::io::Result<()> { let app = Route::new() .nest("/api/auth", auth.clone().poem_endpoint()) .data(auth); Server::new(TcpListener::bind("127.0.0.1:3000")).run(app).await}Extractors
Section titled “Extractors”| Extractor | When there is no valid session |
|---|---|
CurrentSession<S> |
Rejects with 401 |
OptionalSession<S> |
Yields None for any extraction failure — a missing session, missing auth data or a storage error — matching the Axum adapter. Use CurrentSession when failures must be reported |
Both expose user and session in your own model types. The extractors need the same Arc<BetterAuth<S>> installed with .data(auth) on the routes that use them; as in Axum they validate the session cookie.
use crate::auth_schema::AppAuthSchema;use alibi::integrations::poem::OptionalSession;use poem::handler;
#[handler]async fn home(session: OptionalSession<AppAuthSchema>) -> String { match session.0 { Some(_) => "signed in".to_owned(), None => "anonymous".to_owned(), }}Behavior to know
Section titled “Behavior to know”- The endpoint preserves the original URL (even when nested), query parameters, request bytes and repeated response headers, including every
Set-Cookie. - Auth dispatch owns method matching, request protection and plugin hooks; Poem only forwards.
- Request bodies are buffered within the configured
BodyLimitConfigbefore dispatch. - A fully buffered request continues after the client disconnects. Dropping the endpoint drains accepted work while its Tokio runtime remains alive — keep the runtime running during shutdown, because stopping the runtime or process can cancel pending work.
- Dispatch carries auth request context and tracing, not arbitrary application task-local values.
- As with Axum, the client IP comes from proxy headers; configure
advanced.ip_address(Session management).
For CORS, use Poem’s Cors middleware around the nested endpoint (or the builder’s CorsConfig, not both), and add the app origin to trusted_origins.