Server-side Firebase tutorial

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)

  1. 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
  2. Go to https://firebase.google.com/ and start a new project (declining Google Analytics for simplicity).
  3. 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 the get_db function in the ‘store’ server module.
  4. 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.
  5. 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.)
  6. 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]
  7. 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:

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.

9 Likes

Thanks for this. I’ll be giving it a go tomorrow.

1 Like

Just got around to trying this. Instructions are good, my competency is a little lacking.
I’m getting the following error:

ExternalError: FirebaseError: [code=permission-denied]: Missing or insufficient permissions.

** at app/firebase/firebase_client/firestore.py:67*
** called from home, line 49*

It may be that I am using Anvil secrets incorrectly. I created a new secret called credential , clicked on “Set Value” and pasted the contents of the .json text file. Is that incorret?

That sounds correct.

The fact that the error is being triggered from the ‘home’ form rather than the server code, though, makes me think that the error is unrelated to the secret/.json stuff. Did you do the following part of #3 in my instructions?

copy the firebaseConfig info into the init_firebase method of the ‘home’ Form in your Anvil app

In any case, I suspect the issue is with something on your client-side setup rather than the server-side.

Umm strange. Yes, I did copy the firebaseConfig info into the home form and have double checked these to make sure there weren’t any errors.
I’ll try running through it again tomorrow - perhaps I incorrectly set up the project on Firebase.

I have just noticed that there there are entries in the firestore database with “New item (via server)” which is interesting I couldnt see anything happening on the front end.

Anyway, I appear to have broken it so will start from scratch tomorrow and see where I end up.

@email to jump in here really quick.
What you are most likely seeing are the security rules jumping in.
Usually when you start a project they allow access for 30 days.

1 Like

I can confirm that I get the same error message when I change my firestore security rule to simulate the 30 days elapsing.

I’m seeing that the server-side Admin SDK is not constrained by security rules, but the client-side won’t be able to see the changes made server-side if it is not at least given read access.

Thanks @mark.breuss You were absolutely right! I updated the security rules and it worked immediately.

2 Likes

Note: I’ve made a minor change to the server code in the clone-link app to fix the firebase_admin import to work correctly after a change to the Anvil Firebase SDK. For some reason it seems necessary to explicitly import firestore ahead of using it, this way:

  import firebase_admin
  from firebase_admin import firestore

Even though the downstream code still references firebase_admin.firestore rather than just firestore, adding that second import line seems necessary to ensure the import process is complete before attempting to call it.

1 Like