pages.auth_gate

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Declarative auth enforcement from filesystem route metadata.

This is the DECLARATIVE auth gate (awaited per mounted page in app/registry.py). It now delegates to the SAME shared core as the imperative@login_required…

Declarative auth enforcement from filesystem route metadata.

This is the DECLARATIVE auth gate (awaited per mounted page in app/registry.py). It now delegates to the SAME shared core as the imperative@login_required / @requiresdecorators (enforce_auth()), so both paths produce identical 302/401/403 outcomes and identicalemit_security_eventpayloads. pages may depend on security(security primitives sit below pages).

pages.auth_gate

Name Type Default Description
type
qualified_name
element_type
description
source_file
line_number
is_autodoc
autodoc_element
_autodoc_template
_autodoc_url_path
_autodoc_page_type
title
doc_content_hash

Symbols on this page

enforce_route_meta_auth
function async
async def enforce_route_meta_auth(meta: RouteMeta | None, request: Request, *, policy_resolver: PolicyResolver | None = None) -> None

EnforceRouteMeta.authbefore a mounted page handler runs.

authaccepts a plain string (back-compatible) or a structured AuthSpec. String semantics (preserved exactly):

  • None, "", "none", "optional"— no gate
  • "required"— authenticated user required (browser redirect or 401)
  • any other string — treated as a single required permission via UserWithPermissions.permissions

AnAuthSpecadditionally supports permission sets with mode="all" / mode="any"and a named policy. Normalization and enforcement are shared with the decorator path.

policy_resolver maps an AuthSpec.policyNAME to the registered callable (app.register_policy); the page wrapper wires it from the app's policy registry. When a spec names a policy that the resolver cannot resolve (unregistered name, or no resolver wired), the shared core fails LOUD (LookupError-> 500) — a misconfiguration, NOT a 403 auth denial and NOT anauthz.policy.deniedevent. The 500 is only a runtime backstop; the auth_specstartup contract check is the real guard (it ERRORs on any referenced policy name that is not registered).

Parameters

Name Type Default Description
meta RouteMeta | None
request Request
policy_resolver PolicyResolver | None None

View source · /home/runner/work/chirp/chirp/site/../src/chirp/pages/auth_gate.py:1