The following is built upon the wonderful client-side Anvil Firebase SDK. For my use case, I wanted to initiate some firestore updates from the server side. Here is how I first got it working:
(Note: The instructions, as written, require a Paid Anvil plan (Personal+) to work, though Free users could do something similar via Uplink)
- Clone the following Anvil app, built upon the Anvil Firebase example app (noting the custom Python build which includes the necessary server-side packages): Anvil | Login
- Go to https://firebase.google.com/ and start a new project (declining Google Analytics for simplicity).
- Click the “</>” button to add a web app to the project. In step 2 (Add Firebase SDK), copy the firebaseConfig info into the
init_firebase
method of the ‘home’ Form in your Anvil app. Also copy the ‘projectId’ and ‘storageBucket’ codes into theget_db
function in the ‘store’ server module. - Now, back in the Firebase console, click on the gear icon in the upper left next to “Project Overview” and select “Project Settings.” Select the “Service Accounts” tab. With “Firebase Admin SDK” selected, click the “generate new private key” button and click “Generate Key” in the dialog.
- Copy the contents of the .json text file generated by the previous step into an Anvil secret in your app named ‘credential’. (That is, click the “Create new secret” button, enter
credential
as the name, click the “Set value” button, and then paste in the .json contents.) - Back in the Firebase console project overview, click on Cloud Firestore, the click “Create Database” and follow the prompts. (For the location choice, I’m not sure whether it’s better to choose the location closest to your users or choose London, the closest to the Anvil servers.) Choose the Test security rule.[a]
- You should now be able to run the Anvil app and add list items with either the “+ Todo” or “+ Todo (via server)” buttons in the bottom right.
a. Firestore security rules
The Test security rule should look something like the following, which basically says "give client-side read-write access to anyone until 2023-2-26:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if
request.time < timestamp.date(2023, 2, 26);
}
}
}
In a real app you’ll probably want to make the access read-only or else restrict access based on user auth.[b] (Note that these rules only apply to client-side access. The server-side firebase_admin
is not restricted by these security rules.)
b. Firebase user auth.
For Firebase user auth, you’ll need to create a user token using something like this server function (adapted from @mark.breuss’s code):
@anvil.server.callable
def fs_server_get_auth_token():
user = anvil.users.get_user()
user_uid = str(user.get_id())
return firebase_admin.auth.create_custom_token(user_uid).decode("utf-8")
You can then use that token to sign the user in to Firebase client-side using the “Sign in Token” function provided as part of the Anvil Firebase SDK.
p.s. These are the docs I found most helpful for getting started with server-side Firebase:
- https://firebase.google.com/docs/firestore/quickstart?authuser=1#initialize
- https://anvil.works/docs/working-with-files/media#constructing-media-objects
- https://anvil.works/docs/working-with-files/media#files-in-server-modules
- https://firebase.google.com/docs/firestore/manage-data/add-data?authuser=1#add_a_document
p.p.s. As a heads-up, the server-side import of the firebase_admin
seems to take around 3s, so you’ll likely want to put that inside the server function so it’s only imported when needed.