Skip to content

RBAC

Shakti's role-based access control is deliberately simple: every User has a single role string column (default "user"), and Auth.require_role() gives you a dependency that enforces it.

Restricting a route to specific roles

from shakti import Depends
from shakti.auth.models import User

@app.delete("/admin/users/{id:int}")
async def delete_user(id: int, user: User = Depends(auth.require_role("admin"))) -> dict:
    ...

require_role(*roles) first verifies the JWT (same as get_current_user()401 for missing/invalid/expired tokens), then checks user.role against the allowed set, raising 403 with a message naming both the required and actual role if it doesn't match:

@app.get("/reports")
async def reports(user: User = Depends(auth.require_role("admin", "analyst"))) -> dict:
    # allowed if user.role is "admin" OR "analyst"
    ...

Assigning roles

Roles are set at registration or afterward:

admin = await auth.register_user(
    email="admin@example.com", username="admin", password="...", role="admin",
)
# POST /auth/register
{"email": "a@b.com", "username": "alice", "password": "s3cret", "role": "admin"}

To change a user's role later, update it through your own ORM code — there's no built-in "promote user" endpoint, since who's allowed to grant roles is application-specific:

async with db.session() as session:
    user = await session.get(User, user_id)
    user.role = "admin"
    await session.commit()

Roles are just strings

There's no fixed enum of roles — role is a free-form String(50) column, so you can use whatever scheme fits ("user"/"admin", or "viewer"/"editor"/"owner", etc.). If you need more granular permissions than one role per user (e.g. per-resource ACLs), layer that on top with your own Depends() dependency that reads from your own tables — require_role covers the common "is this user in role X" case, not general authorization.

See JWT Auth for how tokens and Depends(auth.get_current_user()) work under the hood.