1

I created a Google Cloud Platform account, and made a simple hello_world type Python "Cloud Function" that just spits out some simple text. I made this function "HTTP" accessible and only able to be called/authenticated by a "Service Account" that I made for the purpose of calling this very function. I generated a key for this "Service Account" and downloaded the json file for the key.

The problem is that I can't find any documentation on how to call this function with my service account in a next.js app. I tried this:

import React from 'react';
import { Button } from 'react-bootstrap';
import { GoogleAuth } from 'google-auth-library';

const projectId = 'gtwitone';
const keyFilename = '/Users/<myusername>/path/to/cloudfunction/credentials.json';

class Middle extends React.Component {
    handleClick() {
        console.log('this is:', this);
      }
    // This syntax ensures `this` is bound within handleClick.  // Warning: this is *experimental* syntax.  handleClick = () => {    console.log('this is:', this);  }

    /* async listFunctions() {
        const [functions] = await client.listFunctions();
        console.info(functions);
    } */

    async runGoogleCloudFunctionTest() {
      // Define your URL, here with Cloud Run but the security is exactly the same with Cloud Functions (same underlying infrastructure)
      const url = "https://us-central1-<projectname>.cloudfunctions.net/<functionname>"
      //Example with the key file, not recommended on GCP environment.
      const auth = new GoogleAuth({keyFilename: keyFilename})
  
      //Create your client with an Identity token.
      const client = await auth.getIdTokenClient(url);
      const res = await client.request({url});
      console.log(res.data);
    }

    render() {
      return (
        <div className="col-md-12 text-center">
            <Button variant='primary' onClick={this.runGoogleCloudFunctionTest}>
                Click me
            </Button>
        </div>
      );
    }
  }

export default Middle;

But I got this error in my terminal:

<myusername>@<mycomputername> <thisnextjsappdirectory> % yarn dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
wait  - compiling...
event - compiled client and server successfully in 267 ms (124 modules)
wait  - compiling / (client and server)...
wait  - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'

Import trace for requested module:
./node_modules/google-auth-library/build/src/index.js
./components/Middle.tsx
./pages/index.tsx

https://nextjs.org/docs/messages/module-not-found
Native Node.js APIs are not supported in the Edge Runtime. Found `child_process` imported.

Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
^C
<myusername>@<mycomputername> <thisnextjsappdirectory> % 

I know that this is problem with server side rendering in my Next.js app and people recommend using a client side package like this https://github.com/google/google-api-javascript-client. But google-api-javascript-client doesn't have any documentation on authenticating with a .json credentials file instead of an API KEY which I do not have.

In short how do I get my app to work and run the Google Cloud function with a .json credentials file for am authenticated service account?

3
  • 1
    Can you check this documentation if this helps you? Commented May 2, 2022 at 9:12
  • Hi. Did it solve your issue? Else we can see where you are getting stuck and we can work on it. Please respond if the issue is solved on your end or not. Commented May 3, 2022 at 9:39
  • 1
    Yes, I just posted an answer that worked for me Commented May 3, 2022 at 21:19

1 Answer 1

3

I fixed it by simply moving the GoogleAuth api call to the pages/api route.

pages/api/google.ts

// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"
import { GoogleAuth } from "google-auth-library"

export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
    const url = process.env.FUNCTION_URL as string

    //Example with the key file, not recommended on GCP environment.
    const auth = new GoogleAuth({ keyFilename: process.env.KEYSTORE_PATH })

    //Create your client with an Identity token.
    const client = await auth.getIdTokenClient(url)
    const result = await client.request({ url })
    console.log(result.data)
    res.json({ data: result.data })
}

components/Middle.tsx

import React from "react"
import { Button } from "react-bootstrap"

class Middle extends React.Component {
  handleClick() {
        console.log("this is:", this)
    }
  
  // this talks with /pages/api/google
  async imCallingAnAPI() {
    const result = await fetch("/api/google")
    console.log({ result })
  }

  render() {
    return (
      <div className="col-md-12 text-center">
        <Button variant="primary" onClick={this.imCallingAnAPI}>
          Click me
        </Button>
      </div>
    )
  }
}

export default Middle

pages/index.tsx

import type { NextPage } from 'next'
import Header from '../components/Header';
import Footer from '../components/Footer';
import Middle from '../components/Middle';

const Home: NextPage = () => {
  return (
    <><main className='d-flex flex-column min-vh-100'>
      <Header />
      <br></br>
      <br></br>
      <Middle />
      </main>
      <footer>
        <Footer />
      </footer>
    </>
  )
}

export default Home

I think that next.js has trouble loading GoogleAuth in a component. I'm not 100% sure why, but I think it has to do with next.js not knowing exactly how to handle GoogleAuth with server-side rendering.

Sign up to request clarification or add additional context in comments.

1 Comment

Fwiw, I ran into this issue and found that nextjs edge runtime runs with a js runtime that does not include nodejs core modules that are required by the google libraries and I found that switching the route in question to use nodejs instead of edge worked around the issue in my case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.