1. Authentication vs Authorization
- Auhentication: “Who are you?” Verifies identity via passwords, OAuth, biometrics, etc.
- Authorization: “What can you do?” Decides permissions after login.
Think of it like a nightclub: Authentication is the bouncer checking your ID. Authorization is deciding if you can enter the VIP lounge.
Common Auth Methods:
- JWT (JSON Web Tokens): Stateless, popular for APIs.
- Sessions: Cookie-based for web apps.
- OAuth2/OpenID Connect: For social logins.
2. Role-Based Access Control (RBAC)
Assign roles (e.g., admin, editor, viewer) to users, and map roles to permissions (e.g., read:posts, delete:users).
Why RBAC?
- Simple & Scalable: Great for teams with clear hierarchies.
- Pros: Easy to audit, low overhead.
- Cons: Rigid for complex scenarios (e.g., “edit only your own docs”).

Real-World Example: In a blog app:
Admin: All permissions.Editor: Create/edit posts.Viewer: Read only.
RBAC with FastAPI
Use dependency injection for clean enforcement.
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
import jwt
app = FastAPI()
security = HTTPBearer()
# Simulate users
USERS = {
"alice": {"role": "admin"},
"bob": {"role": "editor"}
}
SECRET_KEY = "secret-key"
class User(BaseModel):
username: str
role: str
def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
username = payload.get("sub")
user = USERS.get(username)
if not user:
raise HTTPException(status_code=401, detail="Invalid user")
return User(username=username, role=user["role"])
except:
raise HTTPException(status_code=401, detail="Invalid token")
def require_role(required_role: str):
def role_check(user: User = Depends(get_current_user)):
if user.role != required_role:
raise HTTPException(status_code=403, detail="Insufficient permissions")
return user
return role_checker
@app.post("/posts")
def create_post(user: User = Depends(require_role("editor"))):
return {"msg": f"Post created by {user.username}"}
@app.delete("/users")
def delete_user(user: User = Depends(require_role("admin"))):
return {"msg": "User deleted"}How to Test:
- Generate JWT:
jwt.encode({"sub": "alice"}, SECRET_KEY, algorithm="HS256") - Hits
/postswithAuthorization: Bearer <token>.
3. Attribute-Based Access Control (ABAC)
ABAC is the flexible beast: Decisions based on attributes of user, resource, action, and environment. No rigid roles but pure policies.
Example Attributes:
- User:
department=HR,clearance=3 - Resource:
owner=alice,sensitivity=high - Environment
time=9am,location=office
When to Use ABAC Over RBAC?
- Dynamic rules (e.g., “HR can view payrool only during business hours”).
- Multi-tenant apps.
- Complex compliance (GDPR, HIPAA). See More
ABAC: Simple Policy Example
Use py-abac for production (pip install py-abac). Here is a lightweight version:
from fastapi import Depends, HTTPException
from pydantic import BaseModel
class ABACRequest(BaseModel):
user: dict # e.g., {"department": "HR", "clearance": 3}
resource: dict # e.g., {"owner", "alice"}
action: str
def abac_policy(req: ABACRequest):
# Policy: HR can read their own docs; clearance > 2 for sensitive
if req.action == "read":
if req.user["department"] == "HR" and req.resource["owner"] == req.user.get("name"):
return True
if req.user["clearance"] > 2:
return True
return False
@app.get("/docs/{doc_id}")
def read_doc(doc_id: int, user: dict = Depends(get_current_user)): ## Assume user from JWT
resource = {"owner": "alice", "sensitivity": "high"} # From DB
req = ABACRequest(user=user, resource=resource, action="read")
if not abac_policy(req):
raise HTTPException(403, "Access denied")
return {"doc": "Secret payrool data"}Note: For scale, try Casbin (mixes RBAC + ABAC) or Cerbos.
4. Auth0
Auth0 handles everything. No reinventing the wheel. Following are the features it offers:
- Universal Login, SSO, MFA, Passwordless.
- Social/Enterprise logins (Google, Azure AD).
- RBAC/ABAC out-of-the-box.
- Actions (custom logic hooks).
Step-by-Step: Auth0 + FastAPI
- Setup Auth0:
- Sign up at Auth0
- Create an API (for backend) + Application (for frontend).
- Note: Domain, Client ID, Audience.
- Protect Endpoints (JWT Validation):
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer
from jose import jwt, JWTError
from auth0.authentication import GetToken # For token exchange if needed
app = FastAPI()
security = HTTPBearer()
AUTH0_DOMAIN = "your-domain.auth0.com"
API_AUDIENCE = "your-audience"
ALGORITHMS = ["RS256"]
def verify_token(credentials: HTTPBearer = Depends(security)):
token = credentials.credentials
try:
payload = jwt.decode(
token,
key=f"https://{AUTH0_DOMAIN}/.well-known/jwks.json", # Auto-fetches
audience=API_AUDIENCE,
algorithms=ALGORITHMS
)
return payload # Contains user_id, permissions, etc.
except JWTWrror:
raise HTTPException(401, "Invalid token")
@app.get("/protected")
def protected(user: dict = Depends(verify_token)):
return {"msg": f"Hello, {user.get('sub')}!"}RBAC in Auth0:
- In Auth0 Dashboard: Assign Roles + Permissions to users.
- In token:
permissionsarray (e.g.,["read:posts"]). - Check:
if "read:posts" not in user.get("permissions", []): raise 403
