rpmjp/projects/skillbridge/auth_deps.py
CompletedFebruary – April 2026
SkillBridge AI — Test Prep Academy Platform
Multi-tenant AI learning platform for test prep academies. Socratic AI tutor that refuses to give answers, AI quiz generation from uploaded files, async pre-grading, weak-spot detection, and AI parent summaries. Full role-based platform across admin, instructor, student, and parent.
LIVE DEMOPython 3.12FastAPIPostgreSQL 16SQLAlchemy 2.0ReactTypeScriptTailwindGroq / Llama
Languages
Python54.2%
TypeScript45.1%
CSS0.3%
JavaScript0.2%
Dockerfile0.1%
Mako0.1%
auth_deps.py
"""FastAPI auth dependencies.
Every protected endpoint depends on get_current_user (decode JWT, load user).
require_role is a dependency factory for role-gated endpoints — the role check
runs before any handler code, so there's no path to a protected endpoint that
skips it. This is the enforcement point for the role-filtering half of the
multi-tenancy model.
"""
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session
from app.db.session import get_db
from app.models.user import User, UserRole
from app.services.auth_service import get_user_from_token
# tokenUrl points to the form-based login endpoint for the Swagger Authorize button.
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login/form")
def get_current_user(
token: str = Depends(oauth2_scheme),
db: Session = Depends(get_db),
) -> User:
"""Decode the JWT and load the user. The user carries the tenant_id that
scopes every downstream query — tenant is derived from identity here,
never from a client-supplied request parameter."""
return get_user_from_token(db, token)
def require_role(*allowed_roles: UserRole):
"""Dependency factory for role-gated endpoints.
Usage:
@router.post("/quizzes/generate")
def generate(user: User = Depends(require_role(UserRole.INSTRUCTOR, UserRole.ADMIN))):
...
The returned dependency runs before the handler. A student hitting an
instructor-only endpoint gets a 403 before any handler logic executes.
"""
def _checker(current_user: User = Depends(get_current_user)) -> User:
if current_user.role not in allowed_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Insufficient permissions",
)
return current_user
return _checker