Skip to content

Authentication

quadkit-auth provides authentication and authorization — JWT, OAuth2, password hashing, and role-based access control (RBAC). In a web application, most checks happen in the request pipeline using guards.

From a scaffolded app:

Terminal window
quadkit add auth

Config lives in application.yaml under auth:. Pair it with the web-api template from Your First App.


graph TD
    Req[Client Request] --> MW[Middleware: CORS / CSRF / Auth]
    MW --> Route[Router: match path]
    Route --> Guard[Guards: authenticate & authorize]
    Guard --> Handler[Controller handler]
ComponentScopeRunsUsed for
MiddlewareGlobalOutermostCORS, CSRF, rate limiting, auth context
GuardPer route/controllerAfter routingAuthentication, role checks

Apply guards to a controller or a single handler with @use_guards. The built-in AuthGuard requires a valid session or token; RoleGuard restricts by role.

from quadkit.web import Controller, get
from quadkit.web.security import use_guards, AuthGuard, RoleGuard
class ProfileController(Controller):
prefix = "/api/profile"
@get("/")
@use_guards(AuthGuard)
async def me(self) -> dict:
return {"status": "authenticated"}
@use_guards(RoleGuard("admin", authorizer=authorizer)) # applies to every route in the controller
class AdminController(Controller):
prefix = "/admin"

RoleGuard needs an AuthorizerProtocol instance — resolve it from the container (or constructor-inject it into the controller) and pass it at guard instantiation.

quadkit.web also re-exports concise shortcuts:

from quadkit.web import roles, guard
@roles("admin", "editor") # require any of these roles
@guard(MyCustomGuard) # apply a custom guard

AuthGuard and RoleGuard are abstract base classes — implement your own by subclassing and returning either success or a GuardRejection. Request data is available through the typed Request (e.g. request.ip, request.user):

from quadkit.web.security import AuthGuard
from quadkit.web import Request
class IPAllowlistGuard(AuthGuard):
allowed = {"127.0.0.1", "10.0.0.1"}
async def can_activate(self, request: Request) -> bool:
return request.ip in self.allowed

See the quadkit-auth package docs for the exact guard interface and built-in guards.


When a guard rejects a request, QuadKit returns a standardized HTTP error (as RFC 7807 Problem Details):

FailureHTTP status
Not authenticated401
Authenticated but not authorized403

Because the framework uses the Result pattern, services can also return auth errors directly and the web layer maps them to the right status code.


quadkit add auth writes the dependency and the YAML section. You can also add the provider by hand:

from quadkit.auth import AuthBundleProvider
app.add_provider(AuthBundleProvider())
application.yaml
auth:
enabled: true
token:
secret_key: "${ORI_AUTH__TOKEN__SECRET_KEY}"
algorithm: HS256
access_token_expire: 30m
password:
min_length: 12
require_uppercase: true
require_digits: true
rbac:
enabled: true
default_role: viewer