Ojasa Mirai

Ojasa Mirai

FastAPI

Loading...

Learning Level

🟢 Beginner🔵 Advanced
🚀 Authentication Basics📚 API Keys📚 Basic Auth📚 JWT Tokens📚 OAuth2📚 Scopes📚 Securing Endpoints📚 Token Refresh📚 Role-Based Access
Fastapi/Authentication/Role Based Access

Role Based Access

Learn the fundamentals of role based access in FastAPI.

🎯 Core Concept

Role-Based Access Control (RBAC) allows you to grant permissions based on user roles. Different roles have different permissions, enabling fine-grained authorization in your API.

📖 What You'll Learn

In this section, you'll understand:

  • Defining roles and permissions
  • Checking user roles in endpoints
  • How it applies to real-world API development
  • Common patterns and best practices

💡 Basic Role Checking

from typing import List
from enum import Enum

class UserRole(str, Enum):
    ADMIN = "admin"
    MODERATOR = "moderator"
    USER = "user"

class User(BaseModel):
    id: int
    username: str
    email: str
    role: UserRole

@app.get("/admin/stats")
async def get_admin_stats(current_user: User = Depends(get_current_user)):
    if current_user.role != UserRole.ADMIN:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only admins can access this"
        )
    return {"users": 1000, "revenue": 50000}

@app.post("/posts/")
async def create_post(post: PostCreate, current_user: User = Depends(get_current_user)):
    if current_user.role not in [UserRole.ADMIN, UserRole.MODERATOR]:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Only admins and moderators can create posts"
        )
    return {"id": 1, **post.dict()}

🔍 Dependency-Based Role Checking

async def require_admin(current_user: User = Depends(get_current_user)):
    if current_user.role != UserRole.ADMIN:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin access required"
        )
    return current_user

async def require_moderator_or_admin(current_user: User = Depends(get_current_user)):
    if current_user.role not in [UserRole.ADMIN, UserRole.MODERATOR]:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Moderator or admin access required"
        )
    return current_user

# Usage
@app.get("/admin/users", dependencies=[Depends(require_admin)])
async def list_all_users():
    return db.get_all_users()

@app.delete("/posts/{post_id}", dependencies=[Depends(require_moderator_or_admin)])
async def delete_post(post_id: int, current_user: User = Depends(get_current_user)):
    # User already verified as moderator/admin
    return db.delete_post(post_id)

💼 Production RBAC System

class Permission(str, Enum):
    READ = "read"
    CREATE = "create"
    UPDATE = "update"
    DELETE = "delete"
    MANAGE_USERS = "manage_users"
    MANAGE_ROLES = "manage_roles"

# Define role permissions
ROLE_PERMISSIONS = {
    UserRole.ADMIN: [
        Permission.READ,
        Permission.CREATE,
        Permission.UPDATE,
        Permission.DELETE,
        Permission.MANAGE_USERS,
        Permission.MANAGE_ROLES
    ],
    UserRole.MODERATOR: [
        Permission.READ,
        Permission.CREATE,
        Permission.UPDATE,
        Permission.DELETE
    ],
    UserRole.USER: [
        Permission.READ,
        Permission.CREATE
    ]
}

def check_permission(required_permission: Permission):
    async def permission_checker(current_user: User = Depends(get_current_user)):
        user_permissions = ROLE_PERMISSIONS.get(current_user.role, [])

        if required_permission not in user_permissions:
            logger.warning(f"User {current_user.id} attempted unauthorized action: {required_permission}")
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"Permission denied: {required_permission}"
            )
        return current_user
    return permission_checker

# Usage
@app.post("/posts/", dependencies=[Depends(check_permission(Permission.CREATE))])
async def create_post(post: PostCreate):
    return {"id": 1, **post.dict()}

@app.delete("/posts/{post_id}", dependencies=[Depends(check_permission(Permission.DELETE))])
async def delete_post(post_id: int):
    return {"status": "deleted"}

@app.post("/users/ban/{user_id}", dependencies=[Depends(check_permission(Permission.MANAGE_USERS))])
async def ban_user(user_id: int):
    db.ban_user(user_id)
    logger.info(f"User {user_id} banned")
    return {"status": "banned"}

How it applies to real-world API development

RBAC is essential for:

  • **Multi-tenant applications**: Different customers have different roles
  • **E-commerce platforms**: Customers, sellers, admins with different permissions
  • **Content platforms**: Writers, editors, reviewers with escalating permissions
  • **Enterprise systems**: Fine-grained access control across departments

Example - E-commerce platform:

class EcomRole(str, Enum):
    ADMIN = "admin"
    VENDOR = "vendor"
    CUSTOMER = "customer"

@app.post("/products/", dependencies=[Depends(check_permission(Permission.CREATE))])
async def create_product(product: ProductCreate, current_user: User = Depends(get_current_user)):
    if current_user.role == EcomRole.VENDOR:
        product.vendor_id = current_user.id
    elif current_user.role == EcomRole.ADMIN:
        # Admin can create products for any vendor
        pass
    return db.create_product(product)

@app.get("/analytics", dependencies=[Depends(check_permission(Permission.MANAGE_USERS))])
async def get_analytics(current_user: User = Depends(get_current_user)):
    if current_user.role == EcomRole.VENDOR:
        return db.get_vendor_analytics(current_user.id)
    else:  # ADMIN
        return db.get_global_analytics()

Common patterns and best practices

  • ✅ Define roles clearly and document permissions
  • ✅ Store roles in database, include in JWT claims
  • ✅ Use dependency injection for role checking
  • ✅ Log authorization failures for audit trails
  • ✅ Use permission-based checks for flexibility
  • ✅ Implement role hierarchy if applicable
  • ✅ Review permissions regularly
  • ✅ Test authorization thoroughly
  • ✅ Never trust client-provided role information
  • ✅ Implement role changes securely

🔑 Key Takeaways

  • ✅ Understand the purpose of role based access
  • ✅ Know when to apply this pattern
  • ✅ Recognize its benefits in real-world scenarios
  • ✅ Be prepared to use it in your projects

Ready to explore more? Check out the advanced section for production patterns and edge cases.


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn