Skip to content

bfabric-asgi-auth: customizable renderer, error classification#493

Open
leoschwarz wants to merge 8 commits intomainfrom
feat/bfabric-asgi-auth-improvements
Open

bfabric-asgi-auth: customizable renderer, error classification#493
leoschwarz wants to merge 8 commits intomainfrom
feat/bfabric-asgi-auth-improvements

Conversation

@leoschwarz
Copy link
Copy Markdown
Member

@leoschwarz leoschwarz commented Apr 27, 2026

Summary

Widens extension points in bfabric_asgi_auth so downstream apps (zip-browser was the driver) can supply their own copy, branding, and error semantics without subclassing the renderer. Six bundled improvements:

  • Configurable redirect statusredirect_status kwarg on PlainTextRenderer and HTMLRenderer, default 303 See Other.
  • Path allowlistunauthenticated_paths: Sequence[str | re.Pattern] on BfabricAuthMiddleware so healthchecks/static assets bypass auth.
  • Token error classificationBfabricTokenValidationFailedError.is_expired flag (in bfabric core) + the strategy classifies into expired/invalid/network/unknown, surfaced as discriminated error_types (token_expired, token_invalid, token_network, token_unknown).
  • Renderer copy hooks — callable error_message(error_type, default) and error_title(error_type, status, default) on HTMLRenderer for per-error-type copy.
  • B-Fabric branding defaultsbfabric_branding=True ships a wordmark + accent colour + return-to-B-Fabric footer; bfabric_url, logo_html, footer_html, back_link override; bfabric_branding=False opts out.
  • on_reject contract — now returns ErrorResponse | RedirectResponse | None instead of bool. The old True "exit silently" path was broken (response never sent); removing it cleans up the contract.

README updated with the VisibleException pattern for app-defined error_types raised inside on_success (B5 from the port notes — no middleware change needed, just docs).

Review notes

  • ~300 lines, 13 files. Three new unit test files (23 new tests) + two existing BDD assertions migrated 302→303.
  • Cross-package change is small: 8 lines in bfabric/src/bfabric/errors.py adding the is_expired attribute.
  • All 117 bfabric_asgi_auth tests pass; 388 bfabric core tests pass; basedpyright clean on touched files.
  • Driven by /Users/leo/code/web-apps/zip-browser/docs/bfabric-asgi-auth-port-notes.md.

Breaking changes

  • AuthHooks.on_reject return type changed (boolErrorResponse | RedirectResponse | None). AuthHooks is a Protocol with a default implementation, so only apps that actively override on_reject need to update — currently zip-browser plus internal usage.
  • Default redirect status moved from 302 to 303. Set redirect_status=302 on the renderer to keep legacy behaviour.

…list

Driven by the zip-browser port. Six bundled improvements:

- Configurable redirect status (default 303 See Other) on both renderers.
- Path allowlist on the middleware (str + re.Pattern) for healthchecks.
- Token validation error classification: BfabricTokenValidationFailedError
  gains is_expired; the strategy maps to expired/invalid/network/unknown;
  ErrorResponse.invalid_token emits a discriminated error_type.
- HTMLRenderer customization: callable error_message / error_title hooks
  let apps inject per-error-type copy.
- Default-on B-Fabric branding (wordmark, accent, return-to-B-Fabric link)
  with bfabric_url, logo_html, footer_html, back_link overrides.
- AuthHooks.on_reject now returns ErrorResponse | RedirectResponse | None
  instead of bool. Removes the broken silent-handle path.
- README updates the VisibleException pattern for app-defined error_types
  raised inside on_success.
…ricTokenInvalidError subclasses

Idiomatic exception hierarchy in place of the boolean discriminator. Callers
that care about a specific kind catch the subclass; callers that handle any
validation failure still catch the parent. Strategy dispatch becomes
ordered except clauses with no per-attribute branching.
…ubclasses

Two reportCallIssue / reportArgumentType entries no longer trigger now that
BfabricTokenExpiredError / BfabricTokenInvalidError have typed constructors,
so the baseline shrinks accordingly.
…criminator

Type-safe enum members (TokenErrorKind.EXPIRED, etc.) at the producer side
(strategies + middleware); StrEnum equality keeps string-keyed lookups working
inside ErrorResponse.invalid_token. Re-exported from the package root so apps
can import it directly.
A better solution exists for the public-paths use case; remove the
allowlist parameter, helper, and accompanying tests/docs to keep the
middleware surface focused.
…enErrorKind

Replace the plain-str signature with the StrEnum so misspellings fail at
the type level instead of silently falling back to "unknown". Switch the
classification dict to enum keys and look up with [] so a future enum
addition that forgets to register copy fails loudly.
@leoschwarz leoschwarz changed the title bfabric-asgi-auth: customizable renderer, error classification, path allowlist bfabric-asgi-auth: customizable renderer, error classification May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant