Broken Access Control in Fastapi with Jwt Tokens
Broken Access Control in Fastapi with Jwt Tokens
Broken Access Control occurs when API endpoints do not properly enforce authorization checks, allowing an authenticated user to access or modify resources that should be restricted. In Fastapi, using JSON Web Tokens (JWT) for authentication is common, but if authorization is not explicitly validated for every request, the system becomes vulnerable. JWT Tokens contain claims such as user identity and roles, but the mere presence of a valid token does not guarantee that the caller is allowed to perform a specific action on a specific resource.
When Fastapi endpoints rely only on authentication (token verification) without implementing robust authorization logic, attackers can manipulate identifiers or elevate privileges. For example, an authenticated user might change a numeric resource ID in the URL to access another user's data, a scenario commonly categorized as BOLA/IDOR. Even with JWT Tokens verifying identity, missing property-level or object-level authorization checks means the API trusts the client to determine what they are allowed to see or change.
Another vector involves role-based access control embedded in the JWT claims. If Fastapi routes check for the presence of a role claim but do not validate that the role has precise, granular permissions, privilege escalation can occur. An attacker could tamper with token contents if signing is misconfigured or exploit endpoints that do not validate scopes properly. Inconsistent enforcement across endpoints—such as applying strict checks in one service but not another—amplifies the risk.
Input validation also intersects with access control. If Fastapi accepts user-supplied identifiers (e.g., org_id, project_id) and uses them to query databases without verifying that the authenticated subject has rights to that identifier, an attacker can traverse relationships horizontally or vertically. This is especially risky when JWT Tokens include tenant or organization claims but the API does not enforce tenant isolation in every query.
Finally, insecure default configurations can compound the issue. For instance, if Fastapi dependencies that verify JWT Tokens are optional or omitted on certain routes, some paths remain accessible to unauthenticated or insufficiently authenticated users. Without systematic, endpoint-level authorization checks aligned with the principle of least privilege, JWT-based authentication alone cannot prevent Broken Access Control.
Jwt Tokens-Specific Remediation in Fastapi
Remediation centers on explicitly validating permissions for each request, using the information within JWT Tokens but never trusting them implicitly. Below are concrete code examples that demonstrate secure patterns in Fastapi, including dependency injection for authentication and granular authorization checks.
from fastapi import Fastapi, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from typing import Optional
app = Fastapi()
security_scheme = HTTPBearer()
# Configuration (use environment variables in production)
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
# Mock data representing authorization rules
# In practice, load from a database or policy engine
user_roles = {
"alice": ["admin"],
"bob": ["user"],
}
required_scopes = {
"/items/{item_id}": ["read:item"],
"/items/{item_id}": ["write:item"],
}
def decode_token(token: str) -> dict:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token expired",
headers={"WWW-Authenticate": "Bearer"},
)
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)
def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security_scheme)):
payload = decode_token(credentials.credentials)
# Ensure essential claims exist
if "sub" not in payload:
raise HTTPException(status_code=400, detail="Missing subject claim")
return payload
def authorize_scope(required_scopes: list[str], token_payload: dict):
token_scopes = token_payload.get("scope", "").split()
if not any(s in token_scopes for s in required_scopes):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Insufficient scope",
)
@app.get("/items/{item_id}")
def read_item(
item_id: int,
token_payload: dict = Depends(get_current_user),
):
# Example of object-level authorization: ensure user can access this item
# In a real app, query your data layer to confirm the relationship
authorized_items = get_items_user_can_access(token_payload["sub"])
if item_id not in authorized_items:
raise HTTPException(status_code=403, detail="Access to this item denied")
authorize_scope(["read:item"], token_payload)
return {"item_id": item_id, "owner": token_payload["sub"]}
@app.post("/items/{item_id}")
def update_item(
item_id: int,
payload: dict,
token_payload: dict = Depends(get_current_user),
):
if item_id not in get_items_user_can_access(token_payload["sub"]):
raise HTTPException(status_code=403, detail="Access denied")
authorize_scope(["write:item"], token_payload)
# Proceed with update logic
return {"status": "updated"}
def get_items_user_can_access(user_id: str) -> list[int]:
# Replace with actual data access logic
# Ensure tenant/isolation checks are applied here
return [1, 2, 3]
Key remediation practices include:
- Always verify JWT Tokens via a dedicated dependency, and decode them in a way that validates signature, issuer, audience, and expiration.
- Implement object-level checks (e.g., confirm the resource belongs to the user or tenant) rather than relying solely on role claims.
- Use scope-based authorization for fine-grained permissions, and validate scopes on each relevant endpoint.
- Centralize authorization logic where possible (e.g., policies or services) to avoid inconsistencies across routes.
- Ensure tenant isolation in data queries to prevent horizontal privilege escalation across organizations or users.