Authentication Flow
Relevant source files
The following files were used as context for generating this wiki page:
Hodor implements a single-password authentication gate to protect upstream web applications. It operates as a reverse proxy that intercepts all incoming requests to determine if they meet specific access criteria before forwarding them to the configured upstream service.
The system supports three distinct methods of clearing the gate: public path matching, session cookie validation, and IP-based bypass. If a request fails all these checks, Hodor renders a login page and requires the user to submit the correct shared password.
Request Authorization Logic
The proxy_or_login handler in src/proxy.rs serves as the primary entry point for all proxied traffic. It evaluates the request context against the application state to resolve an AuthMethod.
The system evaluates authorization in a strict order of precedence. A request is proxied if it matches a path in BYPASS_PATHS, provides a valid hodor session cookie, or originates from a CIDR listed in BYPASS_CIDRS. Sources: src/proxy.rs:56-78, README.md:144-152
Authentication Methods
When a request clears the gate, Hodor injects the X-Hodor-Auth header to inform the upstream how the request was authenticated.
| Method | Header Value | Condition |
|---|---|---|
| Public | public | Request path matches an entry in BYPASS_PATHS. |
| Password | password | Request contains a valid, signed HMAC session cookie. |
| Bypass | bypass | Resolved client IP matches an entry in BYPASS_CIDRS. |
Sources: src/proxy.rs:24-34, README.md:213-221
Login Process
The login flow handles password submission, validation, and session issuance. It includes security measures to prevent brute-force attacks.
Sequence of Login Operations
- Rate Limit Check: The system validates the client IP against in-memory login records to enforce a limit of 5 attempts per 60 seconds. Sources: src/auth.rs:77-80, README.md:157-157
- Body Collection: Hodor collects the request body, capped at 16 KiB, with a 10-second timeout to prevent Slowloris-style attacks on the login form. Sources: src/auth/form.rs:11-12, README.md:162-162
- Password Verification: The system compares the submitted password with the configured
PASSWORDusing constant-time comparison via thesubtlecrate to mitigate timing attacks. Sources: src/auth.rs:90-97 - Session Issuance: Upon success, Hodor generates a signed token, sets a
hodorcookie, and redirects the user to the original destination. Sources: src/auth.rs:101-114
Session Security and Cookies
Hodor uses HMAC-SHA256 signatures to ensure session integrity without requiring a database.
Token Structure
A session token follows the format <unix_expiry>|<hex_signature>. The signature is calculated by hashing the expiry timestamp using a SECRET key.
Sources: src/auth/session.rs:65-71
// src/auth/session.rs:66-71
pub(crate) fn sign_token(secret: &[u8], expiry: u64) -> String {
let expiry = expiry.to_string();
let mut mac = HmacSha256::new_from_slice(secret).expect("valid HMAC key");
mac.update(expiry.as_bytes());
let signature = hex::encode(mac.finalize().into_bytes());
format!("{expiry}|{signature}")
}
Cookie Configuration
The session cookie is configured with the following attributes:
- HttpOnly: Prevents client-side scripts from accessing the cookie.
- SameSite=Lax: Balances security and usability for cross-site requests.
- Secure: Only included if
SECURE_COOKIEis set totrue(requires HTTPS). - Max-Age: Determined by the
SESSION_TTLconfiguration (default 24h). - Domain: Optional; allows sharing sessions across subdomains.
Sources: src/auth/session.rs:40-52, src/config.rs:25-45
Brute-Force Protection
Hodor implements tiered protections against automated password guessing:
- Failure Delay: Every failed attempt triggers a mandatory 500ms sleep before responding. Sources: src/auth.rs:27, src/auth.rs:96
- Escalating Lockouts: After 10 consecutive failures, the IP is locked out for 60 seconds. Subsequent failures double the lockout duration up to a maximum of 1 hour. Sources: README.md:159-159
- In-memory Tracking: The system tracks up to 10,000 unique IP addresses in memory, evicting the oldest entries when the limit is reached. Sources: README.md:164-164
Public Path and IP Bypasses
BYPASS_PATHS allows specific endpoints to skip authentication. Hodor checks for exact matches or prefix matches using /*. Sources: src/auth/bypass_path.rs, README.md:179-195
BYPASS_CIDRS permits traffic from trusted networks without a password. This is typically used for internal tools or trusted VPNs like Tailscale. If TRUST_PROXY is enabled, Hodor extracts the client IP from the X-Forwarded-For header, provided it comes from a TRUSTED_PROXY_CIDRS source. Sources: src/proxy.rs:48-55, src/config.rs:114-118