Guide: RBAC¶
Wire role_adapter, seed roles from config, set default_role, and protect routes with require_role / require_permission. This is the wiring the basic example omits.
Install¶
main.py¶
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
from fastauth import FastAuth, FastAuthConfig
from fastauth.adapters.sqlalchemy import SQLAlchemyAdapter
from fastauth.api.deps import require_auth, require_permission, require_role
from fastauth.providers.credentials import CredentialsProvider
from fastauth.types import UserData
adapter = SQLAlchemyAdapter(engine_url="sqlite+aiosqlite:///./auth.db")
config = FastAuthConfig(
secret="change-me-in-production-min-32-bytes!!",
providers=[CredentialsProvider()],
adapter=adapter.user,
token_adapter=adapter.token,
roles=[
{"name": "admin", "permissions": ["users:read", "users:write", "users:delete"]},
{"name": "user", "permissions": ["profile:read", "profile:write"]},
],
default_role="user",
)
auth = FastAuth(config)
auth.role_adapter = adapter.role # <-- required
@asynccontextmanager
async def lifespan(app: FastAPI):
await adapter.create_tables()
await auth.initialize_roles() # <-- required to seed roles
yield
app = FastAPI(lifespan=lifespan)
auth.mount(app)
@app.get("/dashboard")
async def dashboard(user: UserData = Depends(require_auth)):
return {"hello": user["email"]}
@app.get("/admin")
async def admin_area(user: UserData = Depends(require_role("admin"))):
return {"message": "Welcome, admin", "user_id": user["id"]}
@app.get("/reports")
async def reports(user: UserData = Depends(require_permission("users:read"))):
return {"message": "Here are your reports", "user_id": user["id"]}
Bootstrap the first admin¶
A fresh DB has no admin role assigned. You have two options:
- Via the admin endpoint, once someone is already admin — chicken-and-egg on a fresh DB.
- Direct DB insert — insert a row into
fastauth_user_rolesfor your user and"admin":
from sqlalchemy import insert
from fastauth.adapters.sqlalchemy.models import UserModel, user_roles, RoleModel
# inside an async session:
async with adapter._session_factory() as session:
user = await session.scalar(select(UserModel).where(UserModel.email == "you@example.com"))
await session.execute(insert(user_roles).values(user_id=user.id, role_name="admin"))
await session.commit()
Try it¶
# Register — you get the default "user" role.
curl -X POST http://localhost:8000/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"a@b.com","password":"s3cur3-pw!"}'
# Inspect your roles:
curl http://localhost:8000/auth/roles/me -H "Authorization: Bearer $ACCESS"
# -> {"user_id":"...","roles":["user"],"permissions":["profile:read","profile:write"]}
# /reports needs "users:read" — fails for "user":
curl http://localhost:8000/auth/reports -H "Authorization: Bearer $ACCESS"
# -> 403 "Insufficient permissions"
Where to go next¶
- RBAC feature — admin endpoints for managing roles at runtime.
- Hooks —
modify_jwtto embed roles/permissions into the token.