Configuration: HTTP basic authentication
This page documents the basic_auth directive for configuring HTTP Basic Authentication for request-level access control. Only hashed passwords are supported — plaintext passwords are rejected at configuration validation time for security reasons.
Global directives
basic_auth_concurrency
{
basic_auth_concurrency 64
}This is a global-only directive that limits the number of concurrent password verification tasks across all basic_auth blocks. Password hashing is computationally expensive, and this limit prevents a flood of authentication requests from exhausting server resources.
| Value type | Description | Default |
|---|---|---|
<positive integer> | Maximum concurrent password verification tasks. | 128 |
false | Disable the limit (unlimited concurrency). | disabled |
Configuration example — reduce concurrency:
{
basic_auth_concurrency 32
}Configuration example — disable the limit:
{
basic_auth_concurrency false
}Configuration example — set minimum of 1:
{
basic_auth_concurrency 1
}- Values less than
1are treated as1. - Setting this too low may cause authentication requests to queue under load, increasing latency.
- Setting this to
falseremoves the limit entirely — use only if you understand the resource implications. - When the limit is reached, additional authentication requests will wait until a slot becomes available rather than being rejected.
basic_auth
example.com {
basic_auth {
realm "Restricted Area"
users {
alice "$argon2id$v=19$m=19456,t=2,p=1$..."
bob "$argon2id$v=19$m=19456,t=2,p=1$..."
}
brute_force_protection {
enabled true
max_attempts 5
lockout_duration "15m"
window "5m"
}
}
}Multiple basic_auth blocks can be defined — users from all blocks are merged.
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
realm | <string> | Authentication realm shown in the browser auth dialog. | Restricted Access |
users | block | User credentials block (username to hash mappings). Required. | — |
brute_force_protection | block | Brute-force attack protection settings. | enabled (see below) |
users block
Each entry inside the users block maps a username to a hashed password:
users {
alice "$argon2id$v=19$m=19456,t=2,p=1$..."
bob "$argon2id$v=19$m=19456,t=2,p=1$..."
}Only hashed passwords are accepted. The following hash formats are supported:
| Prefix | Algorithm |
|---|---|
$argon2id$ | Argon2id (recommended) |
$argon2i$ | Argon2i |
$argon2d$ | Argon2d |
$pbkdf2$ | PBKDF2 |
$pbkdf2-sha256$ | PBKDF2-SHA256 |
$scrypt$ | scrypt |
- It’s recommended to use
ferron-passwdutility (that comes with Ferron) to generate the password hashes. - The
realmvalue is shown in the browser’s authentication dialog. - Configuration validation fails if any password value is not a recognized hash format.
brute_force_protection block
Brute-force protection is enabled by default to protect against credential-guessing attacks.
| Nested directive | Type | Default | Description |
|---|---|---|---|
enabled | <bool> | true | Whether brute-force protection is active. |
max_attempts | <int> | 5 | Maximum failed attempts before lockout. |
lockout_duration | <duration> | 15m | How long to lock the account after exceeding max attempts. |
window | <duration> | 5m | Sliding window for counting attempts. |
Duration strings accept suffixes: 30s, 15m, 1h, 1d. Plain numbers without a suffix are treated as seconds.
Authentication flow
- The stage extracts the
Authorization: Basic <credentials>header from the request. - If the header is missing or malformed, a 401 response is returned with a
WWW-Authenticatechallenge. - The credentials are decoded from base64 (
username:password). - Brute-force lockout is checked — if the IP is locked, the request is rejected immediately with a 429 response.
- The username is looked up in the configured
usersblock. - If the user exists, the password is verified against the stored hash.
- On success,
ctx.auth_useris set to the authenticated username. - On failure, the attempt is recorded and a 401 response is returned.
Forward proxy (CONNECT) support
When a CONNECT request is received and authentication fails, a 407 Proxy Authentication Required response is returned instead of 401.
Brute-force protection behavior
When brute-force protection is enabled:
- Each failed authentication attempt is recorded per-IP with a timestamp.
- If
max_attemptsfailures occur within thewindowduration, the IP is locked. - During lockout, all authentication attempts for that IP are rejected immediately.
- After
lockout_duration, the lockout expires and the attempt history is reset.
Stage ordering
The basic_auth stage runs early in the pipeline:
- After
client_ip_from_header(ensures accurate remote address) - Before
forward_proxy(auth before forwarding) - Before
reverse_proxy(auth before proxying) - Before
static_file(auth before serving files)
Examples
Basic authentication with Argon2 hashes
admin.example.com {
basic_auth {
realm "Admin Panel"
users {
admin "$argon2id$v=19$m=19456,t=2,p=1$c2FsdHNhbHQ$..."
}
}
root /var/www/admin
}Forward proxy with authentication
proxy.example.com {
basic_auth {
realm "Proxy Access"
users {
user1 "$argon2id$v=19$m=19456,t=2,p=1$..."
user2 "$argon2id$v=19$m=19456,t=2,p=1$..."
}
brute_force_protection {
max_attempts 3
lockout_duration "30m"
window "10m"
}
}
forward_proxy {
allow_domains "example.com" "*.example.com"
allow_ports 80 443
}
}Disabling brute-force protection
example.com {
basic_auth {
realm "Behind WAF"
users {
deploy "$argon2id$v=19$m=19456,t=2,p=1$..."
}
brute_force_protection {
enabled false
}
}
}Disabling brute-force protection exposes your users to credential-guessing attacks. Only do this if you have equivalent protection at another layer.
Security considerations
- Always use TLS. Basic Auth credentials are sent in the
Authorizationheader, which is base64-encoded (not encrypted). Without TLS, credentials can be intercepted in transit. - Use Argon2id. This is the recommended algorithm for password hashing — it is resistant to GPU-based attacks and side-channel attacks.
- Use strong passwords. The security of the hash depends on the entropy of the original password.
- Plaintext passwords are rejected. This module does not support plaintext passwords at all.
- Brute-force protection is enabled by default. This provides a reasonable baseline of protection without requiring additional configuration.
- Tune
basic_auth_concurrencyto your workload. Setting it too low may cause authentication queuing under high load; setting it too high may allow a flood of expensive hash operations to exhaust resources.
Best practices
The following best-practice checks are reported by ferron doctor for directives on this page.
basic_auth_concurrency false— Disabling the global password-verification concurrency limit removes backpressure on expensive hash checks. Keep a bounded limit.- Non-Argon2id password hashes — Prefer Argon2id for new Basic Auth credentials. Other hash algorithms are weaker against offline attacks.
brute_force_protection { enabled false }— Disabling credential-guessing protection removes a layer of security. Only disable when equivalent protection exists at another layer.