Integrate Firestore as the policy storage for Casbin with Python/Flask stack
The fundamental way to integrate Firestore as the policy storage for Casbin is by using a dedicated Adapter. In Casbin, an adapter serves as the persistent layer, handling the LoadPolicy() and SavePolicy() operations between the in-memory enforcer and the database.
Since you are using a Python/Flask stack, you'll need the appropriate Python Firestore Adapter for Casbin [1].
1. Prerequisites and Installation
To set up Firestore persistence for your Python Casbin enforcer, you need to install the necessary packages and ensure your Google Cloud credentials are configured.
-
Casbin: The core Casbin library.
pip install pycasbin -
Firestore Adapter: While there isn't one official adapter maintained by the core Casbin team for Python and Firestore, community-maintained packages exist, such as
pycasbin-firebase-adapter[2] (which uses the Firebase Admin SDK to access Firestore).pip install pycasbin-firebase-adapter firebase-admin -
Authentication: Ensure the environment where your Flask app runs (e.g., GCP App Engine, Cloud Run, GKE) has the necessary IAM permissions to access Firestore, or that you have set up a service account key [3].
2. Setting up the Adapter and Enforcer
The setup involves two main steps: initializing the Firebase Admin SDK and then passing the initialized object to the Casbin Adapter constructor.
A. Initialize Firebase Admin SDK
The Casbin Firestore adapter relies on the Firebase Admin SDK to communicate with the database.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
# --- 1. Load Credentials ---
# Best practice on GCP (e.g., Cloud Run) is to use Application Default Credentials (ADC).
try:
cred = credentials.ApplicationDefault()
firebase_admin.initialize_app(cred)
except:
# Fallback for local testing (replace with your path)
cred = credentials.Certificate("path/to/serviceAccountKey.json")
firebase_admin.initialize_app(cred)
db = firestore.client()
B. Create and Use the Casbin Adapter
Now, you pass the initialized Firestore client (db) to the adapter, and then pass the adapter to the Casbin Enforcer.
import casbin
from pycasbin_firebase_adapter import Adapter as FirestoreAdapter # Rename for clarity
# 1. Instantiate the Adapter, pointing it to your Firestore client
# Note: The adapter may allow specifying a collection name (e.g., 'casbin_rules').
adapter = FirestoreAdapter(db)
# 2. Instantiate the Enforcer with your model and the new adapter
# 'model.conf' contains the definition of your access control model (e.g., RBAC).
e = casbin.Enforcer("model.conf", adapter)
# --- Policy is automatically loaded into memory here (LoadPolicy()) ---
# 3. Enforcement Check (Uses the in-memory policy)
sub = "alice"
obj = "/reports/finance"
act = "read"
if e.enforce(sub, obj, act):
print(f"{sub} is permitted to {act} {obj}.")
else:
print(f"{sub} is denied access to {obj}.")
Annotation: When the Enforcer is created, the Adapter's LoadPolicy() method is called, which fetches all policy rules (p, g, g2) from Firestore and loads them into Casbin's in-memory model.
3. Policy Management in Firestore
Once the adapter is set up, you manage all policy rules using the Casbin API; you never interact directly with the Firestore collection for Casbin rules.
A. Saving New Policies
When you make changes using the Casbin management API, the adapter automatically translates those changes into Firestore documents.
| Casbin API Call | Firestore Document Action |
|---|---|
e.add_policy("editor", "/data", "write") | Creates a new document in the Casbin collection (e.g., ptype: p, v0: editor, v1: /data, v2: write). |
e.add_grouping_policy("user_x", "editor") | Creates a new document (e.g., ptype: g, v0: user_x, v1: editor). |
e.save_policy() | Overwrites the entire policy in Firestore with the current in-memory state (used less frequently). |
B. Firestore Policy Structure
The Firestore adapter typically stores the policy rules as documents in a single collection (e.g., casbin_rules). Each document will have fields corresponding to the Casbin policy line structure:
| Field | Casbin Policy Line Component |
|---|---|
ptype | The policy type (p, g, g2, etc.) |
v0 | The first field (e.g., user or role) |
v1 | The second field (e.g., resource or parent_role) |
v2 to v5 | Subsequent fields (e.g., action or domain) |
This ensures that the NoSQL structure of Firestore can faithfully represent the relational policy rules Casbin uses.
