FastAPI RBAC: Using OAuth2 Scopes for Permissions

Treat OAuth2 scopes as a list of permissions. Instead of checking a user's role, you check if their token has the required scope (e.g., `items:write`) for an endpoint. FastAPI's Security dependency automates this check.
WHY IT EXISTS: To move beyond simple 'logged in vs. not logged in' security. Real applications need to grant different users different levels of access. Role-Based Access Control (RBAC) provides a pattern for managing these permissions, allowing some users to read data while only specific roles can write or delete it.
THE MENTAL MODEL: Think of OAuth2 scopes as a set of keys on a keyring. A user is given a keyring (their JWT) with specific keys (scopes) like read:profile or write:posts. An endpoint is a door with a specific lock. To access the endpoint, the user's keyring must have the matching key. This is more flexible than a single master key (a simple 'admin' role).
HOW IT WORKS: In FastAPI, this pattern involves three steps. First, you define all possible scopes your application uses, for example, {"items:read": "Read items", "items:write": "Write items"}. Second, when a user authenticates (e.g., at the /token endpoint), you determine their permissions and encode the corresponding scopes into their JWT. Third, on protected endpoints, you use a Security dependency. You pass your user-retrieval function and a list of required scopes, like Security(get_current_user, scopes=["items:write"]). FastAPI's dependency injection system automatically decodes the JWT, verifies the user, and checks if the required scope is present in the token. If not, it returns a 403 Forbidden error.
WHEN TO USE IT: Use scopes whenever you have different user types or tiers with varying permissions. It's ideal for APIs where some users are consumers (read-only), some are contributors (read-write), and some are moderators (read-write-delete). This is the standard way to implement RBAC in modern, token-based security systems.
WHEN NOT TO USE IT: For very simple applications where any logged-in user can do everything, requiring scopes adds unnecessary complexity. If your only security check is 'is the user logged in?', a simple user lookup without scope validation is sufficient.
ONE CANONICAL EXAMPLE: A user with a JWT containing scopes: ["read"] tries to access an endpoint decorated with dependencies=[Security(get_current_user, scopes=["write"])]. Even though their JWT is valid, FastAPI will automatically block the request with a 403 Forbidden error because the required 'write' scope is missing from their token.
Read the original → fastapi.tiangolo.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.