Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS Example - Firebase Cloud Functions - Instantiate an Admin SDK Directory service object

Goal

Use googleapis with Firebase Cloud Functions to get a list of all users in my G Suite domain.

Question

How do I Instantiate an Admin SDK Directory service object. I do not see a NodeJS example, and I'm not clear how to setup and make the request with googleapis.

Context

This code runs from Firebase Cloud Functions, and it seems to authenticate okay. Now, how do I setup the service object at //TODO in the following code:

// Firebase Admin SDK
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)

// Google APIs
const googleapis = require('googleapis')
const drive = googleapis.drive('v3')
const gsuiteAdmin = googleapis.admin('directory_v1')

// Service Account Key - JSON
let privatekey = require("./privatekey.json")

let jwtClient = new googleapis.auth.JWT(
    privatekey.client_email,
    null,
    privatekey.private_key,
    ['https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/admin.directory.user'])

// Firebase Cloud Functions - REST
exports.authorize = functions.https.onRequest((request, response) => {
    //authenticate request
    jwtClient.authorize(function (err, tokens) {
        if (err) {
            console.log(err)
            return
        } else {
            console.log("Successfully connected!")
        }

        // TODO
        // USE SERVICE OBJECT HERE??
        // WHAT DOES IT LOOK LIKE?

        response.send("Successfully connected!")
    })
})
like image 547
Chadd Avatar asked Oct 29 '22 23:10

Chadd


1 Answers

Order of Operations:

  1. Create Service Account Credentials in Google Cloud Console
  2. Add Domain-Wide Delegation to the Service Account
  3. Authorize the API in G Suite - Security - Advanced
  4. Go back to the Service Account and Download the .json key file

I downloaded the .json key file too soon, e.g., before authorizing the APIs in G Suite. The order, Setting up the Service Account with DwD and then authorization the API in G Suite API and then downloading the .json key file is important.

The Example

// Firebase Admin SDK
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)

// Google APIs
const googleapis = require('googleapis')
const drive = googleapis.drive('v3')
const directory = googleapis.admin('directory_v1')

// Service Account Key - JSON
let privatekey = require("./privatekey.json")
let impersonator = '[email protected]'

let jwtClient = new googleapis.auth.JWT(
    privatekey.client_email,
    null, // not using path option
    privatekey.private_key,
    ['https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/admin.directory.user',
        'https://www.googleapis.com/auth/admin.directory.user.readonly'],
    impersonator
)

// Firebase Cloud Functions - REST
exports.getUsers = functions.https.onRequest((request, response) => {
    //authenticate request
    jwtClient.authorize(function (err, tokens) {
        if (err) {
            console.log(err)
            return
        } else {
            console.log("Successfully connected!")
        }
        //Google Drive API
        directory.users.list ({
            auth: jwtClient,
            domain: 'example.com',
            maxResults: 10,
            orderBy: 'email',
            viewType: 'domain_public'
          }, function(err, res) {
            if (err) {
              console.log('The API returned an error: ' + err)
              return;
            }
            var users = res.users;
            if (users.length == 0) {
              console.log('No users in the domain.');
            } else {
              console.log('Users:');
              for (var i = 0; i < users.length; i++) {
                var user = users[i];
                console.log('%s (%s)', user.primaryEmail, user.name.fullName)
              }
              response.send(users)
            }        
        })
    })
})

UPDATE

The example above is not secure. A Cloud Function, especially with G Suite Domain-wide Delegation, should not respond to http requests unless they come from your application. See in this example that the Cloud Function uses admin.auth().verifyIdToken(idToken)... to validate that the request is authenticated by Firebase.

If you don't properly handle your G Suite DwD Cloud Function, you risk exposing your G Suite API to the public.

like image 133
Chadd Avatar answered Nov 15 '22 09:11

Chadd