Thomas David Kehoe
Thomas David Kehoe

Reputation: 10930

How to import Google Cloud credentials into a Firebase Cloud Function?

I'm trying to set up Google Cloud Translation in a Firebase Cloud Function. I'm using the demo code provided by Google Cloud Translation:

// Instantiates a client
const translationClient = new TranslationServiceClient();

const projectId = 'languagetwo-cd94d';
const location = 'global';
const text = 'Hello, world!';

async function translateText() {
    // Construct request
    const request = {
        parent: `projects/${projectId}/locations/${location}`,
        contents: [text],
        mimeType: 'text/plain', // mime types: text/plain, text/html
        sourceLanguageCode: 'en',
        targetLanguageCode: 'es',
    };

    // Run request
    const [response] = await translationClient.translateText(request);

    for (const translation of response.translations) {
        console.log(`Translation: ${translation.translatedText}`);
    }
}

translateText();

This demo tutorial makes a second file called key.json:

{
  "type": "service_account",
  "project_id": "myAwesomeApp",
  "private_key_id": "1234567890",
  "private_key": "-----BEGIN PRIVATE KEY-----\noPeeking=\n-----END PRIVATE KEY-----\n",
  "client_email": "[email protected]",
  "client_id": "1234567890",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/translation-quickstart%40myAwesomeApp.iam.gserviceaccount.com"
}

I uploaded my credentials from the CLI:

gcloud auth login 
gcloud iam service-accounts create translation-quickstart --project myAwesomeApp
gcloud projects add-iam-policy-binding myAwesomeApp
gcloud iam service-accounts keys \
    create key.json --iam-account \
    [email protected]
export GOOGLE_APPLICATION_CREDENTIALS=key.json

I then entered node app.js at the CLI and it runs perfectly. ¡Hola Mundo!

How do I import my credentials into a Firebase Cloud Function? I tried this:

exports.ENtranslateES = functions.firestore.document('Users/{userID}/English/Translation_Request').onUpdate((change) => { // triggers when browser writes a request word to the database
    // Google Cloud
    const { TranslationServiceClient } = require('@google-cloud/translate');
    // Instantiates a client
    const translationClient = new TranslationServiceClient();
    const projectId = 'languagetwo-cd94d';
    const location = 'global';
    const text = 'Hello, world!';

    async function translateText() {
        // Construct request
        const request = {
            parent: `projects/${projectId}/locations/${location}`,
            contents: [text],
            mimeType: 'text/plain', // mime types: text/plain, text/html
            sourceLanguageCode: 'en',
            targetLanguageCode: 'es',
        };

        // Run request
        const [response] = await translationClient.translateText(request);

        for (const translation of response.translations) {
            console.log(`Translation: ${translation.translatedText}`);
        }
    }

    return translateText()

});

I added only a return at the bottom because Firebase Cloud Functions require that something has to be returned.

The result is that the function triggers and translateText() fires. Then I get an error message:

Error: 7 PERMISSION_DENIED: Cloud IAM permission 

That looks like the credentials weren't imported. How do I import the key.json credentials into the Firebase Cloud Function?

Upvotes: 1

Views: 455

Answers (2)

Thomas David Kehoe
Thomas David Kehoe

Reputation: 10930

I got Google Cloud Translate to work in Postman. This is a step towards an answer, not an answer. (Google has its own version of Postman, called Google Cloud API, but it doesn't work with Translate,)

I followed this blog post to set up Google Cloud API in Postman. I started at my Google Cloud Console. I selected my project. I clicked APIs & Services, then Credentials, then + Create Credentials, then OAuth client ID. Under Application type I selected Web application. I named the client ID Postman. Lastly I added an Authorized redirect URI: https://console.cloud.google.com/. Now when I click on my Postman API in my Google Cloud Console I see a Client ID and a Client secret.

In Postman, I changed GET to POST and entered the URL from the Google Cloud Translation page:

https://cloud.google.com/translate/docs/reference/rest/v2/translate

Under the Authorization tab I put in:

Token Name: GCP Token
Grant Type: Authorization Code
Callback URL: https://www.getpostman.com/oauth2/callback
Auth URL: https://accounts.google.com/o/oauth2/auth
Access Token URL: https://accounts.google.com/o/oauth2/token
Client ID: 1234567890abc.apps.googleusercontent.com
Client Secret: ABCDE-NoPeeking-1234567890
Scope: https://www.googleapis.com/auth/cloud-platform 
State: 
Client Authorization: Send as Basic Auth header

I then clicked Get New Access Token and an access token appeared at the top of all this. The token is good for one hour.

Under Params I entered:

q: rain
target: es
source: en

Google Cloud Translate returned lluvia.

Now I know what the auth properties and query parameters are. I don't know how to put them into a Firebase Cloud Function.

Upvotes: 0

John Hanley
John Hanley

Reputation: 81424

Normally, you do not import a service account into a Google compute service such as Cloud Functions. Those services have an attached service account. There are methods of securely storing a service account using services like Google Cloud Secret Manager. In your case there is a better solution.

The following line in your source code uses the Cloud Function attached service account, which defaults to the App Engine default service account [email protected].

const translationClient = new TranslationServiceClient();

Since you did not specify a credential when creating the translationClient, ADC (Application Default Credentials) searches for credentials. In your example, the search found valid credentials from the Cloud Function service account.

The solution is to add the required role to that service account.

If you want to use the service account that you created, then attach the service account identity (email address) to the Cloud Function link.

Access control with IAM

Upvotes: 1

Related Questions