Skip to content

Authentication & Authorization

FastPluggy ships a minimal auth layer built on Starlette's AuthenticationMiddleware. Auth backends are provided by plugins (e.g. auth_user) and auto-wired at startup.

How it works

  1. No auth plugin installed → all routes are open, request.state.current_user is FPAnonymousUser
  2. Auth plugin installed (e.g. auth_user) → the plugin calls fast_pluggy.set_auth_manager(backend) during on_load_complete, which adds AuthenticationMiddleware and enables auth checks on all core routes

You can also pass an auth manager explicitly:

fast_pluggy = FastPluggy(app, auth_manager=my_custom_backend)

If set explicitly, plugins will not override it.

set_auth_manager(backend)

Sets the auth backend at runtime. Called automatically by auth plugins, but can also be used programmatically:

fast_pluggy.set_auth_manager(my_backend)

This: - Sets self.auth_manager - Adds Starlette's AuthenticationMiddleware - Updates the auth_enable template global

Dependencies

from fastpluggy.core.auth import require_authentication, require_role

require_authentication

Rejects unauthenticated requests (401) or redirects to login if the auth backend defines on_authenticate_error. When no auth manager is set, this is a no-op — all requests pass through.

# Protect an entire router
app.include_router(my_router, dependencies=[Depends(require_authentication)])

# Or a single route
@router.get("/secret", dependencies=[Depends(require_authentication)])
async def secret(request: Request): ...

require_role(role: str)

Requires the user to have a specific role (checked against request.auth.scopes). FastPluggy uses "fp_admin" to protect its own admin routes. No-op when auth manager is not set.

app.include_router(admin_router, dependencies=[Depends(require_role("fp_admin"))])

Current user

Set by CurrentUserMiddleware on every request:

user = request.state.current_user   # FPAnonymousUser if not authenticated
if user.is_authenticated:
    ...
if user.is_admin:
    ...

Available in templates as {{ request.state.current_user }}.

FPAnonymousUser extends Starlette's UnauthenticatedUser and is used as the fallback when no user is authenticated. It guarantees request.state.current_user is never None.

The user object shape depends on the auth backend. FastPluggy core expects:

Attribute Type Description
is_authenticated bool False for anonymous, True for logged-in users
display_name str Shown in the topbar user menu
is_admin bool Controls visibility of the admin sidebar section
profile_picture str\|None Optional; used for avatar display

Writing a custom auth backend

Implement AuthInterface (extends Starlette's AuthenticationBackend):

from fastpluggy.core.auth.auth_interface import AuthInterface

class MyAuthManager(AuthInterface):
    @property
    def user_model(self):
        return MyUserModel

    async def authenticate(self, conn):
        # Return (AuthCredentials, user) or None
        ...

    async def on_authenticate_error(self, request):
        # Return a Response (e.g. redirect) or raise HTTPException
        ...

Then either pass it to FastPluggy(app, auth_manager=MyAuthManager()) or call fast_pluggy.set_auth_manager(MyAuthManager()) from a plugin's on_load_complete.