2

I want to communicate with the Dialogflow CX API from my React application. The relevant code looks like this:

componentWillMount() {
    let payload = {
        "queryInput": {
            "text": {
                "text": "Hi!"
            },
            "languageCode": "en"
        },
        "queryParams": {
            "timeZone": "America/Los_Angeles"
        }
    }
    axios.post('https://global-dialogflow.googleapis.com/v3/' + this.state.projectId + '/sessions/' + this.state.sessionId + ':detectIntent', payload)
        .then(response => {
            this.setState({ dialogResponse: response });
        })
        .catch(error => {
            console.log(error)
        })

    console.log(this.state.dialogResponse)
}

However, the response is 401.

I have create a service account and downloaded the private key as a JSON file as per https://cloud.google.com/docs/authentication/.

How do I then use this to authenticate my API call?

Teresa
  • 353
  • 1
  • 5
  • 27
  • Hi! Maybe it's a stupid observation but Google doesn't allow API use until you've activated it from the cloud console: you need to go to the cloud console page (console.cloud.google.com), then in the left pane click on APIs and services, then in blue under the search bar "enable APIs and services". finally search Dialogflow API and enable that for your billing account. Did you do that? – fcagnola Feb 18 '21 at 15:21
  • Yes, I did that! – Teresa Feb 22 '21 at 10:07
  • Are you able to run the same API in postman? Also is there an error message in the 401 response? – Tarun Lalwani Feb 22 '21 at 15:40

2 Answers2

2

According to the docs, using the service account key (the one you downloaded as a JSON file) is only for

Accessing private data on behalf of a service account outside Google Cloud environments

These are used when:

  1. a user is not present to authenticate; or
  2. server-side requests which do not need a user.

For your use case I assume it's for the latter since you are using Dialogflow. Move this api call on your server side code for example by setting up a cloud function, lambda, or expressjs app running somewhere.

Do not run this request on React for 2 main reasons:

  1. React is Client-side which means users will have access to your source code including your private key. Big security risk.
  2. Dialogflow does not need a user to be authenticated to work.

To add the authentication on your request and use Dialog CX you may follow these steps which are loosely based from here. Take note, these steps are for when your server is running in or outside GCP. Google has a built in functionality if your code runs within GCP but I'll explain the one that works everywhere instead. All of this should be within your cloud function/lambda/expressjs app so if you are not familiar with that research how to set one up and how you can call this within React first.

  1. install dot-env and require it npm install dotenv or yarn add dotenv
  2. require dotenv within app require('dotenv').config()
  3. Download private key json save it somewhere in your project folder)
  4. add .env to your .gitignore file if it isn't there yet
  5. create .env file and add this inside it GOOGLE_APPLICATION_CREDENTIALS="[PATH TO YOUR PRIVATE KEY]"
  6. install Dialogflow CX library npm install @google-cloud/dialogflow-cx
  7. Use the Dialogflow library according to its docs here. The private service key will be automatically detected when using the library.
  8. On production, make sure to add GOOGLE_APPLICATION_CREDENTIALS="[PATH TO YOUR PRIVATE KEY]" as an environment variable to cloud function, lambda, docker or whatever you will be using.

As an added note, refresh your private keys and remove it from your React Project folder if you have already committed them to your github repo.

lvillacin
  • 154
  • 7
0

In the end, I couldn't get it to work by adding the JSON credentials to .env (did install dotenv). What I ended up doing:

  • Move the API call to my Express server

  • Add the JSON file to my project folder

  • Use the @google-cloud/dialogflow-cx library as follows:

     const { SessionsClient } = require('@google-cloud/dialogflow-cx');
     const client = new SessionsClient({
       keyFilename: "./my-file-name.json" //include the JSON file here!
     });
    
     ...
    
     app.get('/input', async (req, res, next) => {
       try {
         const sessionId = Math.random().toString(36).substring(7);
         const sessionPath = client.projectLocationAgentSessionPath(
           projectId,
           location,
           agentId,
           sessionId
         );
         console.info(sessionPath);
    
     const request = {
       session: sessionPath,
       queryInput: {
         text: {
           text: 'Hi there',
         },
         languageCode,
       },
     };
    
     const [response] = await client.detectIntent(request);
     for (const message of response.queryResult.responseMessages) {
       if (message.text) {
         console.log(`Agent Response: ${message.text.text}`);
       }
     }
     if (response.queryResult.match.intent) {
       console.log(
         `Matched Intent: ${response.queryResult.match.intent.displayName}`
       );
     }
     console.log(
       `Current Page: ${response.queryResult.currentPage.displayName}`
     );
    

    } catch (error) { return next(error) } })

Teresa
  • 353
  • 1
  • 5
  • 27