Broken Authentication in Fastapi with Firestore
Broken Authentication in Fastapi with Firestore — how this specific combination creates or exposes the vulnerability
Broken Authentication occurs when identity management functions are implemented incorrectly, allowing attackers to compromise passwords, keys, or session tokens. In a Fastapi application using Google Cloud Firestore as the user store, the risk arises from a mismatch between Fastapi's authentication mechanics and Firestore's security model. Common patterns include storing passwords as plaintext or with weak hashing, using predictable or missing session identifiers, and exposing Firestore document IDs in URLs without ownership checks.
Fastapi relies on explicit dependency injection for authentication. If a developer writes an authenticate_user dependency that queries Firestore by a user-supplied identifier (e.g., email) but does not enforce constant-time password verification, timing attacks can leak valid accounts. For example, an attacker can send login requests with many emails and measure response time to infer which emails exist in Firestore.
Firestore itself does not enforce authentication; it enforces security rules. If security rules are misconfigured—such as allowing read or write access based only on document ID equality without verifying the requesting user's identity—any authenticated API route that references a user-supplied document ID can become an Insecure Direct Object Reference (IDOR). An endpoint like /users/{user_id} that retrieves a Firestore document without confirming that the authenticated user owns that document enables horizontal privilege escalation.
Additionally, Fastapi sessions or JWTs may store user identifiers in claims without proper token binding. If tokens are issued with weak signing algorithms (e.g., none algorithm) or without validating the token issuer and audience, an attacker can forge tokens that Firestore-based authorization logic will trust. This leads to authentication bypass where the API trusts a tampered token and grants access to another user's Firestore data.
Real-world attack patterns include credential stuffing against weak passwords, token replay via insecure storage on the client side, and vertical privilege escalation when role claims are not verified server-side. These issues map directly to OWASP API Top 10 controls for Broken Authentication and can expose sensitive user data stored in Firestore collections.
Firestore-Specific Remediation in Fastapi — concrete code fixes
Remediation centers on secure password handling, strict ownership checks, and properly constrained Firestore security rules. Below are concrete Fastapi code examples that demonstrate a secure pattern for authentication with Firestore.
Secure user registration and login
Use passlib with bcrypt for hashing and constant-time verification. Ensure Firestore queries use indexed fields and avoid leaking existence via timing differences.
from fastapi import Fastapi, Depends, HTTPException, status
from pydantic import BaseModel
from passlib.context import CryptContext
import google.auth.transport.requests
import google.auth.exceptions
from google.cloud import firestore
app = Fastapi()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
db = firestore.Client()
class UserCreate(BaseModel):
email: str
password: str
class UserLogin(BaseModel):
email: str
password: str
def get_user_by_email(email: str):
# Use get-by-index to avoid leaking existence via timing
docs = db.collection("users").where("email", "==", email).limit(1).stream()
for doc in docs:
return {"id": doc.id, **doc.to_dict()}
return None
@app.post("/register")
def register(payload: UserCreate):
if get_user_by_email(payload.email):
raise HTTPException(status_code=409, detail="Email already registered")
hashed = pwd_context.hash(payload.password)
db.collection("users").add({"email": payload.email, "password_hash": hashed})
return {"message": "User created"}
@app.post("/login")
def login(payload: UserLogin):
user = get_user_by_email(payload.email)
if not user:
# Return a generic error to avoid user enumeration
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
if not pwd_context.verify(payload.password, user["password_hash"]):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
# In production, issue a signed JWT with minimal claims and short expiry
return {"message": "Login successful", "user_id": user["id"]}
Authorization with Firestore ownership checks
Always resolve the authenticated subject from the request (e.g., via JWT or session), then enforce ownership at the document path level before any read or write.
from fastapi import Depends
def get_current_user_token():
# Placeholder for JWT or session extraction and validation
return {"sub": "user_abc123"}
@app.get("/users/{user_id}")
def read_user(user_id: str, current_user: dict = Depends(get_current_user_token)):
# Enforce ownership: the path must include the authenticated subject
if user_id != current_user["sub"]:
raise HTTPException(status_code=403, detail="Forbidden")
doc_ref = db.collection("users").document(user_id)
doc = doc_ref.get()
if not doc.exists:
raise HTTPException(status_code=404, detail="Not found")
return {"id": doc.id, **doc.to_dict()}
Firestore security rules to complement Fastapi checks
Security rules should enforce ownership and scope access to a user’s own document. This ensures that even if an API route is misconfigured, rules act as a final constraint.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
By combining these measures—strong hashing, constant-time lookups, ownership-enforced paths, and constrained Firestore rules—you reduce the attack surface for Broken Authentication in a Fastapi + Firestore stack.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |