Michele Volpato

Michele Volpato

Firebase to Google Sheets, a tech security clarification

Tutorials

In a previous article, I show how to synchronize data from Firestore to a spreadsheet in Google Drive using a Cloud Function triggered by the creation of a new document in Firestore.

The approach used in that article, namely, deploying a service account with access to the Google Drive API with the Cloud Functions using it, is not safe.

Here I propose two solutions, both compatible with the rest of the article, that can replace the deployment of the service account with the Cloud Functions.

Add Google Drive API permission to the default service account

When Cloud Functions run, some default authorization credentials are automatically populated. The default service account is in the form PROJECT_ID@appspot.gserviceaccount.com, in my case selling-soul@appspot.gserviceaccount.com, and it is named App Engine default service account.

Default service account

After enabling access to Google Sheets API from the previous article, instead of creating a new service account, you can use the default one.

We need to share the spreadsheet with PROJECT_ID@appspot.gserviceaccount.com, then we use the Application Default Credentials to authorize our request in src/exportBids.ts:

import * as functions from 'firebase-functions'

// Google Sheet
import { google } from 'googleapis'
const sheets = google.sheets('v4')

const authClient = google.auth.getClient({
    scopes: ['https://www.googleapis.com/auth/spreadsheets']
});

export async function exportBids(
    id: string,
    username: string,
    date: string,
    bids: Array<any>
) {

    console.info(`Exporting bids ${id}`)

    const finalData: Array<Array<string>> = []
    bids.forEach(function (bid) {
        finalData.push([id, date, username, bid.bidder, bid.offer])
    })

    await sheets.spreadsheets.values.append({
        auth: await authClient,
        spreadsheetId: "1YpO8oe2I8cEImtKjnBscOLbiNnnTaDP1e82YAaymu20",
        range: `Sheet1!A1:E1`,
        valueInputOption: 'RAW',
        requestBody: { values: finalData, majorDimension: "ROWS" }
    }, {})
}

Using Google Secret Manager

The other solution is to use Google Secret Manager, which we will explain in detail in a future article.

Get a weekly email about Flutter

Subscribe to get a weekly curated list of articles and videos about Flutter and Dart.

    We respect your privacy. Unsubscribe at any time.

    Leave a comment