Authenticating Users on App Engine Using Firebase

This tutorial shows how to retrieve, verify, and store user credentials using Firebase Authentication, the Google App Engine standard environment, and Google Cloud Datastore.

The document walks you through a simple note-taking application called Firenotes that stores users' notes in their own personal notebooks, which are identified by a unique user ID generated by Firebase. The application has the following components:

  • The frontend configures the Firebase Authentication user interface and handles authentication state changes, including retrieval of a Firebase ID token used as an access token.

  • The user interface, called FirebaseUI, is a drop-in solution that handles linking multiple providers to one account, recovering passwords, and much more to provide a sign-in experience that follows best practices for authentication.


  • The backend verifies the ID token and returns user profile information, including the user ID that associates notes with a particular user in the database.

The application stores user credentials in Cloud Datastore by using the NDB client library, but you can store the credentials in a database of your choice.

The following diagram shows how the frontend and backend communicate with each other and how user credentials travel from Firebase to the database.

Architecture Diagram

Firenotes is based on the Flask web application framework. The sample app uses Flask because of its simplicity and ease of use, but the concepts and technologies explored are applicable regardless of which framework you use.


  • Configure the Firebase Authentication user interface.
  • Obtain a Firebase ID token and verify it using server-side authentication.
  • Store user credentials and associated data in Cloud Datastore.
  • Query a database using the NDB client library.
  • Deploy an app to App Engine.


This tutorial uses billable components of Cloud Platform, including:

  • Google Cloud Datastore

Use the Pricing Calculator to generate a cost estimate based on your projected usage. New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Install Git and Python 2.7.
  2. Sign in to your Google account.

    If you don't already have one, sign up for a new account.

  3. Select or create a Cloud Platform Console project.

    Go to the Projects page

  4. Install and initialize the Cloud SDK.

If you have already installed and initialized the SDK to a different project, set the gcloud project to the App Engine project ID you're using for Firenotes. See Managing Cloud SDK Configurations for specific commands to update a project with the gcloud tool.

Cloning the sample app

To download the sample to your local machine:

  1. Clone the sample application repository to your local machine:

    git clone

Alternatively, you can download the sample as a zip file and extract it.

  1. Navigate to the directory that contains the sample code:

    cd python-docs-samples/appengine/standard/firebase/firenotes

Adding the Firebase Authentication user interface

To configure FirebaseUI and enable identity providers:

  1. Add Firebase to your app.
  2. Add your Firebase project ID to the backend's app.yaml file as an environment variable.
  3. Configure the FirebaseUI login widget by selecting which providers you want to offer your users.

    // Firebase log-in widget
    function configureFirebaseLoginWidget() {
      var uiConfig = {
        'signInSuccessUrl': '/',
        'signInOptions': [
          // Leave the lines as is for the providers you want to offer your users.
        // Terms of service url
        'tosUrl': '<your-tos-url>',
      var ui = new firebaseui.auth.AuthUI(firebase.auth());
      ui.start('#firebaseui-auth-container', uiConfig);

  4. Enable the providers you have chosen to keep in the Firebase console.

  5. Click Auth > Sign-in method. Under Sign-in providers, hover the cursor over a provider and click the pencil icon for a given provider.

    Sign in providers

    1. Toggle the Enable button and, for third-party identity providers, enter the provider ID and secret from the provider's developer site. The Firebase docs give specific instructions in the "Before you begin" sections of the Facebook, Twitter, and GitHub guides. After enabling a provider, click Save.

      Toggle enable button

    2. In the Firebase console, under OAuth redirect domains, click Add Domain and enter the domain of your app on App Engine in the following format:


      Do not include http:// before the domain name.

Installing dependencies

Navigate to the backend directory and complete the application setup:

  1. Set up and run a virtual environment:

    pip install virtualenv
    virtualenv env
    source env/bin/activate
  2. Install the third-party requirements that are not included in the App Engine SDK:

    pip install -r requirements.txt -t lib

    In, the vendor.add() method registers the libraries in the lib directory.

  3. Install pycrypto separately:

    pip install pycrypto

    Although the pycrypto library is built into the App Engine standard environment, it will not be bundled until deployment because it is platform-dependent. The app.yaml file includes the bundled version of pycrypto at runtime, but you still need to install it manually to run the application on the App Engine local development server.

Running the application locally

To run the application locally, use the App Engine local development server:

  1. Add the following URL as the backendHostURL in main.js:


  2. Navigate to the root directory of the application. Then, start the development server: frontend/app.yaml backend/app.yaml
  3. Visit http://localhost:8080/ in a web browser.

Authenticating users on the server

Now that you have set up a project and initialized an application for development, you can walk through the code to understand how to retrieve and verify Firebase ID tokens on the server.

Getting an ID token from Firebase

The first step in server-side authentication is retrieving an access token to verify. Authentication requests are handled with the onAuthStateChanged() listener from Firebase:

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    var name = user.displayName;

    /* If the provider gives a display name, use the name for the
    personal welcome message. Otherwise, use the user's email. */
    var welcomeName = name ? name :;

    user.getToken().then(function(idToken) {
      userIdToken = idToken;

      /* Now that the user is authenicated, fetch the notes. */



  } else {


When a user is signed in, the Firebase getToken() method in the callback returns a Firebase ID token in the form of a JSON Web Token (JWT).

Verifying tokens on the server

After a user signs in, the frontend service fetches any existing notes in the user's notebook through an AJAX GET request. This requires authorization to access the user's data, so the JWT is sent in the Authorization header of the request using the Bearer schema:

// Fetch notes from the backend.
function fetchNotes() {
  $.ajax(backendHostUrl + '/notes', {
    /* Set header for the XMLHttpRequest to get data from the web server
    associated with userIdToken */
    headers: {
      'Authorization': 'Bearer ' + userIdToken

Before the client can access server data, your server must verify the token is signed by Firebase. To verify the JWT, you first fetch Firebase certificates that contain public keys that will be used to decrypt the token. You can employ the urlfetch service from the Python App Engine API to retrieve and validate certificates:

# This URL contains a list of active certificates used to sign Firebase
# auth tokens.

def get_firebase_certificates():
    """Fetches the current Firebase certificates.

    Note: in a production application, you should cache this for at least
    an hour.
        result = urlfetch.Fetch(
        data = result.content
    except urlfetch_errors.Error:
        logging.error('Error while fetching Firebase certificates.')

    certificates = json.loads(data)

    return certificates

Next, you need to determine which certificate should be used to check that the token signature is valid. Firebase certificates contain a kid (key ID) field in the header to identify the public key that was used to sign the JWT. To extract the public key from the certificate, use the SSL and Abstract Syntax Notation One (ASN.1) libraries:

def extract_public_key_from_certificate(x509_certificate):
    """Extracts the PEM public key from an x509 certificate."""
    der_certificate_string = ssl.PEM_cert_to_DER_cert(x509_certificate)

    # Extract subjectPublicKeyInfo field from X.509 certificate (see RFC3280)
    der_certificate = asn1.DerSequence()
    tbs_certification = asn1.DerSequence()  # To Be Signed certificate

    subject_public_key_info = tbs_certification[6]

    return subject_public_key_info

Finally, decrypt the token with the public key to get the JWT's payload claims, a set of key-value pairs that contain user profile information:

    claims = jwt.decode(
except jwt.exceptions.InvalidTokenError as e:
    logging.warning('JWT verification failed: {}'.format(e))
    return None

Each identity provider sends a different set of claims, but each has at least a sub claim with a unique user ID and a claim that provides some profile information, such as name or email, that you can use to personalize the user experience on your app.

Managing user data in Cloud Datastore

After authenticating a user, you need to store their data for it to persist after a signed-in session has ended. The following sections explain how to store a note as a Cloud Datastore entity and segregate entities by user ID.

Creating entities to store user data

You can create an entity in Cloud Datastore by declaring an NDB model class with certain properties such as integers or strings. Cloud Datastore indexes entities by kind; in the case of Firenotes, the kind of each entity is Note. For querying purposes, each Note is stored with a key name, which is the user ID obtained from the sub claim in the previous section.

The following code demonstrates how to set properties of an entity, both with the constructor method for the model class when the entity is created and through assignment of individual properties after creation:

data = request.get_json()

# Populates note properties according to the model,
# with the user ID as the key name.
note = Note(
    parent=ndb.Key(Note, claims['sub']),

# Some providers do not provide one of these so either can be used.
note.friendly_id = claims.get('name', claims.get('email', 'Unknown'))

To write the newly created Note to Cloud Datastore, call the put() method on the note object.

Retrieving user data

To retrieve user data associated with a particular user ID, use the NDB query() method to search the database for notes in the same entity group. Entities in the same group, or_ancestor path_, share a common key name, which in this case is the user ID.

def query_database(user_id):
    """Fetches all notes associated with user_id.

    Notes are ordered them by date created, with most recent note added
    ancestor_key = ndb.Key(Note, user_id)
    query = Note.query(ancestor=ancestor_key).order(-Note.created)
    notes = query.fetch()

    note_messages = []

    for note in notes:
            'friendly_id': note.friendly_id,
            'message': note.message,
            'created': note.created

    return note_messages

You can then fetch the query data and display the notes in the client:

// Fetch notes from the backend.
function fetchNotes() {
  $.ajax(backendHostUrl + '/notes', {
    /* Set header for the XMLHttpRequest to get data from the web server
    associated with userIdToken */
    headers: {
      'Authorization': 'Bearer ' + userIdToken
    // Iterate over user data to display user's notes from database.

Deploying your app

You have successfully integrated Firebase Authentication with your App Engine application. To see your application running in a live production environment:

  1. Change the backend host URL in main.js to https://backend-dot-[PROJECT_ID] Replace [PROJECT_ID] with your project ID.
  2. Deploy the application using the Cloud SDK command-line interface:

    gcloud app deploy backend/index.yaml frontend/app.yaml backend/app.yaml
  3. View the application live at https://[PROJECT_ID]

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial, delete your App Engine project:

Deleting the project

The easiest way to eliminate billing is to delete the project you created for the tutorial.

To delete the project:

  1. In the Cloud Platform Console, go to the Projects page.

    Go to the Projects page

  2. Click the trash can icon to the right of the project name.

What's next

Send feedback about...

App Engine standard environment for Python