Skip to content

studyhaxer/day16-role-based-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Day 16 — Role-Based Access Control (FastAPI)

Extends the Day 15 JWT auth API with role-based permissions, reusable query dependencies, and a couple of fixes flagged in the Day 15 review.

Built as part of a daily build-in-public series leading up to a capstone project.

What's new since Day 15

  • Roles: every user now has a role field — "student" or "teacher", defaulting to "student".
  • require_any_role(*roles): a dependency factory that gates a route to one or more roles. Returns a clean 403 Forbidden (not 401) when the user is authenticated but not allowed.
  • Teacher-only course creation: POST /courses now requires the teacher role.
  • Paginated, role-open course listing: GET /courses is open to any authenticated user (student or teacher) and supports limit/offset pagination.
  • Consistent 403s: a custom ForbiddenException so every permission failure across the app returns the same JSON shape.
  • SECRET_KEY via environment variable: no more hardcoded secret. Falls back to a dev-only placeholder locally, and hard-fails on startup if missing in production.

Auth model

Endpoint Who can access Notes
POST /register Anyone Role optional, defaults to student
POST /login Anyone Returns a JWT
GET /me Any authenticated user Returns the caller's own profile
POST /courses Teachers only 403 for students
GET /courses Any authenticated user Paginated
GET /users Any authenticated user Paginated, returns 200 + [] when empty
GET /users/{user_id} Self, or any teacher See decision below
DELETE /users/{user_id} Self only A user can only delete their own account

Decision: who can view GET /users/{user_id}?

A user can view their own profile. A teacher can view any user's profile, including their enrolled courses.

This is a deliberate choice: teachers are treated as trusted staff in this model, with oversight visibility over all students rather than only students enrolled in their own courses. The simpler rule was chosen over a course-scoped check to keep the permission model easy to reason about at this stage of the project; a more granular "teacher can only view students in their own courses" rule is a reasonable next iteration but wasn't required here.

Tech stack

  • FastAPI — web framework
  • SQLAlchemy — ORM, SQLite for local dev
  • python-jose — JWT encoding/decoding
  • passlib (bcrypt) — password hashing
  • Pydantic v2 — request/response schemas

Project structure

.
├── main.py          # routes
├── models.py        # SQLAlchemy models (User, Course)
├── schemas.py       # Pydantic request/response schemas
├── auth.py          # JWT, password hashing, role dependency
├── database.py      # engine, session, Base
├── pagination.py    # shared pagination dependency
├── Exceptions.py    # ForbiddenException (consistent 403s)
└── README.md

Running locally

  1. Clone the repo and install dependencies:

    pip install fastapi uvicorn sqlalchemy python-jose passlib[bcrypt] python-multipart
  2. Set a SECRET_KEY environment variable (required in production, optional locally):

    export SECRET_KEY="your-secret-here"
  3. Run the server:

    uvicorn main:app --reload
  4. Open http://127.0.0.1:8000/docs for the interactive API docs.

Example flow

# Register as a teacher
POST /register
{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "password": "secret123",
  "role": "teacher"
}

# Log in
POST /login
# returns: { "access_token": "...", "token_type": "bearer" }

# Create a course (requires teacher role)
POST /courses
Authorization: Bearer <token>
{ "title": "Intro to Databases" }

Security note

The SECRET_KEY exposed in the Day 15 commit history has been rotated and is no longer in use. Going forward, secrets are sourced from environment variables and excluded from version control via .gitignore.

What's next

Stretch goals for a future pass:

  • Course-scoped permissions for teachers (only view/manage students enrolled in their own courses)
  • Refresh tokens
  • Role-based filtering on GET /users and GET /courses

About

Role-based access control on top of a JWT auth API — FastAPI dependency factories for role gating, reusable pagination, and proper 401 vs 403 semantics. Day 16 of #60DaysOfPython.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages