Skip to content

Bearer Token Guard

bearer_token(*, verify, realm, error_description) — validates HTTP Bearer tokens (RFC 6750) with a caller-supplied verifier function.

Signature

def bearer_token(
    *,
    verify: Callable[[str], AuthUser | None] | Callable[[str], Awaitable[AuthUser | None]],
    realm: str = "lauren",
    error_description: bool = False,
) -> type:
    ...

Parameters:

Parameter Type Default Description
verify callable Sync or async (token) -> AuthUser \| None. Return an AuthUser to allow, None to reject.
realm str "lauren" Realm surfaced in error responses.
error_description bool False Include a short machine-readable reason in the UnauthorizedError detail (missing_token, malformed_header, invalid_token, verifier_error).

Returns: An @injectable(scope=SINGLETON) guard class.

Usage

from lauren import LaurenFactory, controller, get, module, use_guards
from lauren_guards import bearer_token, AuthUser

async def verify_token(token: str) -> AuthUser | None:
    # Replace with DB/cache lookup
    if token == "valid-token":
        return AuthUser(id="u1", roles=("viewer",), scopes=("read",))
    return None

BearerGuard = bearer_token(verify=verify_token)

@use_guards(BearerGuard)
@controller("/api")
class ApiController:
    @get("/data")
    async def data(self) -> dict:
        return {"ok": True}

@module(controllers=[ApiController])
class AppModule:
    pass

app = LaurenFactory.create(AppModule)

Accessing the authenticated user

After successful authentication the guard stores the AuthUser on request.state.user:

from lauren import Request

@controller("/api")
class ApiController:
    @get("/me")
    async def me(self, request: Request) -> dict:
        user = request.state.get("user")  # AuthUser instance
        return {"id": user.id, "roles": list(user.roles)}

You can also use the explicit helpers get_user(request) / set_user(request, user) — see the reference.

Rejection behaviour

When the token is missing, malformed, or rejected by verify, the guard raises UnauthorizedError (HTTP 401). The guard itself does not emit WWW-Authenticate — set error_description=True to include a reason in the error detail if your API needs it.

curl -v http://localhost:8000/api/data
# < HTTP/1.1 401 Unauthorized

Choosing a realm

The realm value appears in the error detail and any custom error handlers you attach. Pick something identifiable (e.g. "Customer API") so clients can tell which credential they need.