crates.io ↗

iet-auth-login-htmx-axum

integration adapter official

Provides the opt-in sign-in page and flow for browser applications.

CoreFeaturesIntegrationsStacksTooling
Used byiet-stack-auth-htmx-axum
iet-auth-login-htmx-axumadapterBrowser login adapter
Depends oniet-telemetrycontractiet-uicontractiet-http-htmx-axumcontractiet-http-axumcontractiet-authcontractiet-corecontract

How to use it

Renders and handles the opt-in browser sign-in page (GET /login, POST /login/submit) with CSRF, session-cookie, redirect, and static-asset handling. You inject a BrowserLogin credential port and a LoginCsrf port (typically SignedCsrf) through routes, register, or register_module.

rust
// crates/integrations/iet-auth-login-htmx-axum/tests/login.rs
use iet_auth_login_htmx_axum::{routes, BrowserLogin, LoginConfig, LoginCsrf};

let router = routes::<(), _, _>(
    Auth, // impl BrowserLogin; returns a BrowserSession token
    Csrf, // impl LoginCsrf, e.g. SignedCsrf
    LoginConfig {
        secure_cookies: false, // local HTTP development only
        session_cookie: "fw_session".into(),
        ..LoginConfig::default()
    },
)?;
  • register merges the routes into an axum::Router<S>; register_module adds them to a RestApi as auth.login.ui plus auth.assets.
  • Configuration is validated up front, e.g. a __Host- cookie name requires secure cookies.

How it works

routes mounts GET {path} and POST {path}/submit; the page handler issues a CSRF token from LoginCsrf, and the submit handler verifies that token, calls BrowserLogin::login, then sets the opaque session cookie and redirects.

flowchart LR
  Get["GET path"] --> Page["login_page"]
  Page --> CsrfIssue["LoginCsrf issue"]
  Page --> View["LoginPage or LoginForm"]
  Post["POST path submit"] --> Submit["login_submit"]
  Submit --> CsrfVerify["LoginCsrf verify"]
  CsrfVerify --> Login["BrowserLogin login"]
  Login --> Cookie["Set-Cookie session"]
  Login --> Redirect["303 or HX-Redirect"]

What it implements

  • Implements iet_auth::Csrf (signed form tokens) from iet-auth.

What's inside

Modules

  • src/assets.rs
  • src/browser.rs
  • src/browser_extract.rs
  • src/flows.rs
  • src/handlers.rs
  • src/lib.rs
  • src/ports.rs
  • src/signed_csrf.rs
  • src/view.rs

Public API

(root)

  • struct LoginConfig
  • pub fn routes<S, A, C>(auth: A, csrf: C, config: LoginConfig) -> AppResult<Router<S>> where S: Clone + Send + Sync + 'static, A: BrowserLogin + Clone + Send + Sync + 'static, C: LoginCsrf + Clone + Se — Register the login page and submission routes on the application's Axum router. The concrete implementations are statically dispatched and stored as router state.
  • pub fn routes_without_assets<S, A, C>(auth: A, csrf: C, config: LoginConfig) -> AppResult<Router<S>> where S: Clone + Send + Sync + 'static, A: BrowserLogin + Clone + Send + Sync + 'static, C: LoginCs — Login endpoints only, for composition with a separately mounted shared asset bundle.
  • pub fn register<S, A, C>( router: Router<S>, auth: A, csrf: C, config: LoginConfig, ) -> AppResult<Router<S>> where S: Clone + Send + Sync + 'static, — Merge the login routes into a state-free Axum router.
  • pub fn register_module<S, A, C, L>( api: RestApi<S, L>, auth: A, csrf: C, config: LoginConfig, ) -> AppResult<RestApi<S, L>> where L: iet_http_axum::RateLimit, — Register the login UI as one named module in an existing REST API router builder.

browser

  • struct BrowserSecurity
  • struct BrowserLimits
  • struct BrowserSession — Authenticated request context. Raw session binding is deliberately private.
  • trait CsrfForm — DTOs explicitly identify their CSRF field; never infer identity from form data.
rust
pub trait CsrfForm {
    fn csrf_token(&self) -> &str;
}
  • pub fn new(auth: A, csrf: C, cookie: impl Into<String>) -> AppResult<Self>
  • pub fn with_limits(mut self, limits: BrowserLimits) -> AppResult<Self>
  • pub fn from_login_config(auth: A, csrf: C, config: &crate::LoginConfig) -> AppResult<Self> — Derive request security from the same login configuration used by the stack, rather than spelling the session cookie twice. Configuration is snapshotted: construct both routers from the finalized configuration.

browser_extract

  • trait BrowserState — Project the security capability from application state without exposing its provider types in every handler. This trait does not protect routes by itself.
rust
pub trait BrowserState: Send + Sync {
    type Auth: Authenticate<Secret<String>>;
    type Csrf: LoginCsrf;
    fn browser_security(&self) -> &BrowserSecurity<Self::Auth, Self::Csrf>;
}
  • struct BrowserIdentity — Authenticated read context with a session-bound form token (never a session secret). Extracting it authenticates once and issues a CSRF token once.
  • struct ProtectedForm — Standalone authenticated mutation extractor. Must be the last extractor because it consumes the request body. Do not pair with BrowserIdentity: authentication is already included. No domain authorization is implied.

flows

  • enum Flow
  • struct ProfileChoice — Only the provider may decide which profiles the current session can use.
  • enum Command — Commands are deliberately typed; raw password/reset/session secrets are never rendered.
  • enum Outcome — Success is rendered generically; profile selection must supply its rotated session.
  • trait BrowserFlow — Implement only the operations registered by your application. page MUST authenticate protected sessions and return only owned/enabled profiles. submit MUST recheck authorization, enforce registration/invitation/password policy, atomically consume reset tokens, deliver reset mail without revealing account existence, revoke sessions on logout, and rotate/revoke old sessions on profile selection. Return success for both known and unknown reset-request identifiers. Backend failures must be errors, not simulated success. Rate limiting belongs to the provider/host.
rust
pub trait BrowserFlow: Clone + Send + Sync + 'static {
    fn page(
        &self,
        flow: Flow,
        session: Option<&Secret<String>>,
    ) -> impl Future<Output = AppResult<Vec<ProfileChoice>>> + Send;
    fn submit(&self, command: Command) -> impl Future<Output = AppResult<Outcome>> + Send;
}
  • pub fn routes<S, P, C>( provider: P, csrf: C, flow: Flow, config: LoginConfig, ) -> AppResult<Router<S>> where S: Clone + Send + Sync + 'static, — Mount a GET form and POST submission at config.path. Does not mount assets: merge [asset_routes] once when composing several account workflows. Defaults are login-oriented: choose a distinct path for every workflow.
  • pub fn asset_routes<S: Clone + Send + Sync + 'static>( config: &LoginConfig, ) -> AppResult<Router<S>> — Mount shared fingerprinted account assets once. Login's existing routes already mount them.

ports

  • trait BrowserLogin — Authenticates credentials and issues an opaque, server-side browser session. The returned secret is the cookie value; implementations must never return a bearer API token or persist the raw value.
rust
pub trait BrowserLogin: Send + Sync {
    fn login(
        &self,
        credentials: &PasswordCredentials,
    ) -> impl Future<Output = AppResult<BrowserSession>> + Send;
}
  • struct BrowserSession — Opaque session cookie value and its expiry.

signed_csrf

  • struct Csrf
  • pub fn new() -> AppResult<Self>

view

  • pub fn render(&self) -> Markup
  • pub fn render(&self) -> Markup

Impl map

  • Default for BrowserLimits
  • FromRequestParts<S> for BrowserIdentity
  • FromRequest<S> for ProtectedForm<T>
  • Default for LoginConfig
  • LoginCsrf for Csrf
  • Authenticate<Secret<String>> for Auth
  • BrowserState for App
  • CsrfForm for Input
  • Validate for Input
  • CsrfForm for Form
  • Validate for Form
  • CsrfForm for InvalidForm
  • Validate for InvalidForm
  • Authenticate<Secret<String>> for FailedAuth
  • BrowserFlow for Provider
  • BrowserLogin for Auth
  • BrowserLogin for BusyAuth

Depends on

External crates: axum, base64, hmac, rand, serde, serde_urlencoded, sha2

Used by

In this repository

  • examples/htmx-starter
  • examples/skills-only-app
  • examples/skills-only-app-task-tracker

Source: crates/integrations/iet-auth-login-htmx-axum