Route Authentication
Fullfinity provides three authentication modes for API routes, allowing fine-grained control over who can access each endpoint.
User Types
Section titled “User Types”Users are classified by their group membership:
| Group Identifier | Name | Description |
|---|---|---|
core_internal | Internal | Backend users with full system access |
core_portal | Portal | External users with limited access (customers, vendors) |
core_public | Public | Guest/anonymous users |
Authentication Dependencies
Section titled “Authentication Dependencies”Use these FastAPI dependencies to protect your routes:
requires_internal
Section titled “requires_internal”Restricts access to internal users only. Use for admin panels, settings, and sensitive operations.
from fastapi import Dependsfrom fullfinity.engine.middleware import requires_internal
@router.post("/api/settings/update", dependencies=[Depends(requires_internal)])async def update_settings(request: Request): # Only internal users can access this passBehavior:
- Returns
401if no valid token - Returns
403if user is not incore_internalgroup
requires_user
Section titled “requires_user”Allows any authenticated user (internal or portal). Use for features accessible to all logged-in users.
from fastapi import Dependsfrom fullfinity.engine.middleware import requires_user
@router.get("/api/my-profile", dependencies=[Depends(requires_user)])async def get_profile(request: Request): # Internal and portal users can access this passBehavior:
- Returns
401if no valid token - Returns
403if user only hascore_publicgroup (guest user)
allows_public
Section titled “allows_public”Allows public access with optional authentication. Tries to authenticate if a token is present, otherwise falls back to guest user.
from fastapi import Dependsfrom fullfinity.engine.middleware import allows_publicfrom fullfinity.engine.context import env_ctx
@router.get("/api/products", dependencies=[Depends(allows_public)])async def list_products(request: Request): # Anyone can access, but authenticated users get personalized results env = env_ctx.get() user = env.user # Either the authenticated user or guest user passBehavior:
- Never returns 401/403
- Always succeeds with either authenticated user or guest user context
- Useful for pages that work for everyone but offer personalization when logged in
No Dependency (Fully Public)
Section titled “No Dependency (Fully Public)”For routes that need no authentication at all (no user context):
@router.get("/api/health")async def health_check(): # No authentication, no user context return {"status": "ok"}Comparison Table
Section titled “Comparison Table”| Dependency | Internal | Portal | Public/Guest | Anonymous |
|---|---|---|---|---|
requires_internal | ✅ | ❌ 403 | ❌ 403 | ❌ 401 |
requires_user | ✅ | ✅ | ❌ 403 | ❌ 401 |
allows_public | ✅ | ✅ | ✅ (as guest) | ✅ (as guest) |
| (none) | ✅ | ✅ | ✅ | ✅ (no user ctx) |
Use Cases
Section titled “Use Cases”Internal Only Routes
Section titled “Internal Only Routes”# Module installation - internal admins only@router.post("/api/modules/install", dependencies=[Depends(requires_internal)])async def install_module(request: Request, module_name: str): pass
# User management@router.get("/api/users", dependencies=[Depends(requires_internal)])async def list_users(request: Request): passPortal + Internal Routes
Section titled “Portal + Internal Routes”# View own orders - any logged-in user@router.get("/api/orders", dependencies=[Depends(requires_user)])async def my_orders(request: Request): env = env_ctx.get() user = env.user # Filter by user's company/permissions pass
# Submit support ticket@router.post("/api/tickets", dependencies=[Depends(requires_user)])async def create_ticket(request: Request): passPublic Routes with Optional Auth
Section titled “Public Routes with Optional Auth”# Product catalog - visible to everyone@router.get("/api/catalog", dependencies=[Depends(allows_public)])async def catalog(request: Request): env = env_ctx.get() user = env.user # Show prices based on user type (guest sees retail, portal sees wholesale) pass
# Website pages@router.get("/{path:path}", dependencies=[Depends(allows_public)])async def web_page(request: Request, path: str): passCombining with Model Access
Section titled “Combining with Model Access”Route authentication works alongside model-level permissions:
- Route level: Controls who can call the endpoint (
requires_internal, etc.) - Model level: Controls CRUD operations per group (see Model Access)
- Record level: Filters visible records per group (see Record Rules)
@router.get("/api/invoices", dependencies=[Depends(requires_user)])async def list_invoices(request: Request): # Route allows portal + internal # But Invoice model access rules determine what each user can read invoices = await Invoice.filter().all() # Automatically filtered by record rules return invoicesNext Steps
Section titled “Next Steps”- Groups and Users - Managing user groups
- Model Access - CRUD permissions per model
- Record Rules - Row-level security