Basic Auth Guard¶
basic_auth(*, verify, realm) — HTTP Basic authentication (RFC 7617).
Signature¶
def basic_auth(
*,
verify: Callable[[str, str], AuthUser | None],
realm: str = "lauren",
) -> type:
...
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
verify |
callable | — | Sync or async (username, password) -> AuthUser \| None. Return an AuthUser to allow, None to reject. |
realm |
str |
"lauren" |
Realm used by basic_auth_challenge_handler for WWW-Authenticate. |
Usage¶
from lauren import LaurenFactory, controller, get, module, use_guards
from lauren_guards import basic_auth, AuthUser
USERS = {"admin": "secret", "alice": "hunter2"}
def verify(username: str, password: str) -> AuthUser | None:
if USERS.get(username) == password:
return AuthUser(id=username, roles=("user",))
return None
BasicGuard = basic_auth(verify=verify, realm="Admin Area")
@use_guards(BasicGuard)
@controller("/admin")
class AdminController:
@get("/dashboard")
async def dashboard(self) -> dict:
return {"panel": "admin"}
@module(controllers=[AdminController])
class AppModule:
pass
app = LaurenFactory.create(AppModule)
In production, replace the in-memory USERS dict with a database lookup and store passwords as hashes via BcryptHasher or Argon2Hasher (never plaintext).
Challenge handler¶
The guard itself raises UnauthorizedError (401). Pair it with basic_auth_challenge_handler in global_exception_handlers to attach WWW-Authenticate: Basic realm="...", charset="UTF-8" to every 401 so browsers show the native credential dialog:
from lauren_guards import basic_auth_challenge_handler
app = LaurenFactory.create(
AppModule,
global_exception_handlers=[basic_auth_challenge_handler],
)
The handler reads the realm the guard recorded on the request, falling back to "lauren".
Browser prompt¶
Browsers automatically show a username/password dialog when they receive a 401 + WWW-Authenticate: Basic realm="..." response, which makes Basic auth useful for quick admin areas without a login form.
Security note¶
Basic auth transmits the password base64-encoded — never use it without TLS (HTTPS) in production.