How to deploy Python Dash app on App Engine, which interacts with Flask app on Cloud Run using Firebase authentication

Takashi Nakamura, PhD
FullStackAI
Published in
10 min readNov 10, 2020

--

In a business context, we are often interested in creating dashboards, which enable us to show images, graphs, tables, etc. There are many frameworks to create dashboards (a.k.a. frontend applications). For Python users, Plotly/Dash would be one of the options. Regarding platforms, Google Cloud Platform (GCP) provides a fully managed serverless platform, App Engine, where we can readily deploy a frontend application.

In a previous article, we discussed how to deploy a Flask app on Cloud Run with authentication. With the previous example, we are going to demonstrate two things:

  1. how to deploy a Dash application on AppEngine;
  2. how to configure the App Engine instance to interact with a Flask application on Cloud Run with authentication.

In terms of the first task, we can find numerous “How To” articles (e.g. by Data Science Campus) since it is not complicated. On the other hand, the second task is not straight-forward. We are going to demonstrate two different authentication methods, using either GCP Service Account Credentials or Firebase SDK in order to establish an interactive frontend on App Engine to Cloud Run instance.

This article is based on an example in the previous article.

Step 1: Create a Dash application

We are interested in a simple Dash application, which enables us to talk to a Cloud Run instance. Note, our Cloud Run instance is protected with Cloud Endpoints. Therefore, we need to keep in mind that:

  1. The frontend (Dash) application sends HTTPS requests to the Cloud Endpoint;
  2. The frontend application creates jwt as the authentication token for Cloud Endpoint.

Regarding the second point, we are going to show an example using a GCP Service Account Credentials first. However, the method is less flexible than an example using Firebase SDK. We will discuss this later.

No authentication process between user and App Engine

In this example, we created a very simple Dash application. The functionality is,

  1. When users click submit_button , create an HTTPS request to Cloud Endpoint instance (endpoint_url ), which is already deployed based on my previous article steps;
  2. jwt is generated by App Engine using a function generate_jwt since a GCP Service Account Credentials file is saved in the same folder;
  3. Once the request is successfully made, display the response from Cloud Run.

Here is a sample code for the Dash application.

Dash application. Create a jwt using a GCP Service Account Credentials

Step 2: Deploy the Dash application on App Engine

We are able to provide our own runtime by supplying a custom Docker image in order to deploy an application on App Engine. In this example, we need six files:

  1. The main python script for Dash (main_v2.py);
  2. Create jwt for authentication (create_jwt_from_sa.py, my_credentials.json);
  3. Configuration file (config_appengine_v2.yaml);
  4. Docker related files (Dockerfile, requirements.txt)
dashapp-ae-v2
├── main_v2.py # Main python file
├── create_jwt_from_sa.py # File to create jwt
├── config_appengine_v2.yaml # Config file for App Engine
├── my_credentials.json # GCP service account credentials
├── requirements.txt # List of python packages
└── Dockerfile # For Docker build

For create_jwt_from_sa.py , you can find the details in my previous post. The details ofDockerfile and config_appengine_v2.yaml are below:

# DockerfileFROM python:3.7.5
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /app
WORKDIR /app
EXPOSE 8050
CMD python main_v2.py

The template for App Engine config file can be found in the link.

# config_appengine_v2.yaml# Run by Python 3.7
runtime: python37
# Machine config https://cloud.google.com/appengine/docs/standard
instance_class: B2
manual_scaling:
instances: 1
# Timeout is 60sec
entrypoint: gunicorn -b :$PORT main_v2:app.server --timeout 60 --workers 1
# Instance name
service: dashapp-ae-v2
handlers:
- url: /.*
script: auto
secure: always

Once these six files are saved in the same directory, deploy the application on App Engine.

$ gcloud app deploy --project=$MY_PROJECT_ID config_appengine_v2.yaml

Go to the App Engine tab on the GCP console. The application is named dashapp-ae-v2. If we have never used App Engine, we might need to create an instance called default . Click the name of the instance and check whether the Dash application is successfully deployed or not.

GCP console, App Engine tab. We can see the deployed Dash application instance

Common error: If we see message Error: Server Error when we open the instance, we need to check out the logs of the instance. Normally we forgot to write specific python packages on requirements.txt .

A typical error message when we could not deploy the instance on App Engine correctly

It is time to check the functionality. If successful, the Dash application on App Engine sends an HTTPS request to Cloud Run, protected by Cloud Endpoint.

Results: The message from the instance is Hello from body, John Doe, which is the expected result. Therefore, we are able to deploy a Dash application on App Engine, which communicates to our existing API on Cloud Run. Great job!

The Dash application on App Engine can talk to Cloud Run API protected by Cloud Endpoint

Step 3: Problem formulation

Someone might have noticed that this application is vulnerable and less flexible as:

  1. The Cloud Run instance is protected by Cloud Endpoint though, the GCP Service Account Credentials file is available on App Engine instance;
  2. Therefore, if anyone knows the App Engine instance location (i.e. URL), they can readily “break into” Cloud Endpoint and Cloud Run instance;
  3. Regarding general web applications, we would like to switch users on the same application; however, the App Engine instance has a single user only — the user of the GCP Service Account Credentials file.

There are multiple techniques to address these three problems, but this article elaborates on a solution using the Firebase account. Firebase is a platform developed by Google for creating a web application and can be readily connected to GCP projects.

Current application

  • Anyone can access the App Engine instance from URL;
  • The App Engine instance owns a GCP Service Account Credentials file (e.g. .json);
  • Therefore, the App Engine instance creates jwt as an authentication token for the Cloud Endpoint;
  • Consequently, anyone can have an access to the Cloud Run instance from the App Engine instance.
Current application: No authentication process between the user and the App Engine instance

Updated application

  • The authentication process is required to access the App Engine instance from URL (based on Firebase);
  • The App Engine instance does not own a GCP Service Account Credentials file;
  • The App Engine instance enables to generate id_token using the Firebase SDK, NOT using a GCP Service Account Credentials file;
  • The Cloud Endpoint instance accepts the id_token, generated based on the Firebase SDK. NOTE: the id_token based on the Firebase pertains to jwt formats.
  • Consequently, anyone, who can have an access to the App Engine instance (in other words, verified users of the web application), is able to talk to the Cloud Run instance.
Updated application: Added an authentication layer between the user and the App Engine instance

Action plans for the updated application

  • Set up Firebase account;
  • Create a web application on Firebase;
  • Update the Dash application adding Firebase login functionality;
  • Update the Cloud Endpoint instance to accept id_token , generated by the Firebase SDK.

Step 4: Set up Firebase account

From the GCP console, go to the Firebase console and “start with your GCP project”.

Once the Firebase account is linked to the GCP project, create a user account from the Authentication menu on the left tab. In this example, the identifier is the user’s email address.

Step 5: Create a web application on Firebase

Next, we create a web application on Firebase, and we are going to connect this web application to our Dash application, using Firebase SDK. The step-by-step official documentation can be found from the link.

First, create a web application from Project Overview.

Register the application with a nickname.

Once the application is created, from the main page, select the application and see Settings.

From Settings, we are able to see Firebase SDK snippet for the web application. We need to use this HTML code snippet for our Dash application.

From Settings, we can find the code snippet

Step 6: Update the Dash application using the HTML snippet

In order to include the Firebase SDK snippet on our Dash application, for convenience, we split the main dash code into two files.

File 1: app.py

app.py initialises Dash application, and includes the Firebase SDK snippet. In short, we would like to create a login page before the main function. To this end, we utilise the idea of Customising Dash’s HTML Index Template to modify the default HTML Index Template. (In app.py example, the idea starts from line 25: app.index_string)

Note: My JavaScript, CSS, HTML knowledge is not as proficient as my Python. Useful links for adding the Firebase SDK snippet on Dash is below:

File 2: main_v3.py

The differences from the previous Dash application (main_v2.py) are below:

  1. The main html.Div is named as main_app_div , which is not visible (style={"display": "none"}) by default;
  2. Once the login is successful (i.e. using Firebase authentication), we are able to fetch id_token;
  3. A new callback and login_process check whether we are able to fetch id_token from cookies. When we can fetch id_token, the main_app_div become visible ({"display": "Block"});
  4. The id_token will be used as jwt for an HTTPS request to Cloud Endpoint (we will configure the Cloud Endpoint instance later).
  5. Therefore, the GCP Service Account Credentials file is not needed.

Note: For simplicity and convenience, the example only focuses on adding Firebase SDK snippet on the Dash application. There are many sophisticated techniques to make the application robust (e.g. using session cookies etc.).

Step 7: Deploy the updated Dash application on App Engine

The updated application needs these five files:

  1. The main python script for Dash (main_v3.py);
  2. A supplemental python file to configure Firebase SDK (app.py);
  3. Configuration file (config_appengine_v3.yaml);
  4. Docker related files (Dockerfile, requirements.txt)
dashapp-ae-v3
├── main_v3.py # Main python file
├── app.py # Sub file including HTML snippet
├── config_appengine_v3.yaml # Config file for App Engine
├── requirements.txt # List of python packages
└── Dockerfile # For Docker build

Note: There are some minor changes in

  1. config_appengine_v3.yaml : Change the entrypoint: and service:
  2. Dockerfile : Change the last line CMD python main_v3.py
# config_appengine_v3.yaml# Run by Python 3.7
runtime: python37
# Machine config https://cloud.google.com/appengine/docs/standard
instance_class: B2
manual_scaling:
instances: 1
# Timeout is 60sec
entrypoint: gunicorn -b :$PORT main_v3:app.server --timeout 60 --workers 1
# Instance name
service: dashapp-ae-v3
handlers:
- url: /.*
script: auto
secure: always

Once all of five files are saved in the same directory, deploy the application on App Engine.

$ gcloud app deploy --project=$MY_PROJECT_ID config_appengine_v3.yaml

Go to the App Engine tab from the GCP console again. Click the new instance dashapp-ae-v3 and check whether the Dash application is successfully deployed or not.

GCP console, App Engine tab. We can see the deployed Dash application instances.

If successful, we are not able to see the main application page, but a login window. In other words, we need to login first before we use the application. This authentication is based on the Firebase account.

Once we fill the registered email address and password on the window, we are able to see the main window, where we are able to create an HTTPS request to the Cloud Endpoint instance.

However, since we have not configured the Cloud Endpoint instance yet, the id_token generated by App Engine is not yet authorised by the Cloud Endpoint instance. Consequently, the message from the instance is {"message":"Jwt issuer is not configured","code":401}.

The id_token generated by the App Engine instance based on Firebase is not authorised by the Cloud Endpoint instance.

Step 8: Update Cloud Endpoint to accept Firebase user accounts

As well as my previous article, we shall configure the Cloud Endpoint instance, which authenticates users based on different methods. Previously, we configured the authentication method using a GCP Service Account Credentials.

To support the Firebase authentication, we need to configure .yaml file again. The official documentation can be found from the link.

The basic structure of the .yaml file is the same as the previous example. We need to add firebase parameters under securityDefinitions and security parameters for paths.

Once the configuration file for Cloud Endpoint is updated, re-deploy two Cloud Run instances (i.e. one for the Flask application, the other of the Cloud Endpoint). The series of actions are summarised in Step 3: Add authentication endpoint on Cloud Run in my previous article.

New Cloud Run instances are deployed. V3 accepts the Firebase id_token.

Step 9: Check the Cloud Endpoint and the Dash application on App Engine

It is time to check the application. To begin with, we need to change the URL on main_v3.py to send an HTTPS request to the updated Cloud Endpoint.

endpoint_url = "https://flaskapp-cr-v3-gateway-yerjarnciq-ue.a.run.app/"

Once re-deployed our Dash application on App Engine, we shall log in to the App Engine instance again and see the response from the Cloud Endpoint instance.

The id_token generated by the App Engine instance based on Firebase is now authorised by the Cloud Endpoint instance.

The id_token generated by the App Engine instance based on Firebase is now authorised by Cloud Endpoint. Well done!

Consequently, we don’t need to deploy instances with a GCP Service Account Credentials file together to create jwt.

Conclusion

The authentication based on Firebase is more elegant and easy to maintain multiple users. Embedding the Firebase SDK on the Dash application was challenging for me at first. Hope this article mitigates the technical difficulties and helps someone who is interested in deploying a multi-user web application on Cloud Run and App Engine.

--

--