user655489
user655489

Reputation: 1326

Working node example of calling google api with jwt for service-to-service call to raw endpoint?

I've been putzing with trying to call the jobs.Insert bigquery rest api endpoint with node (the jobs.Insert method does not seem to be exposed in the bigquery node library).

I've got the Service-to-Service stuff set up so that I can successfully call the methods that the bigquery node library has (create the json file that has the private key, etc. in it for service-to-service calls).

As far as I can tell, I should be able to do call the rest api directly with a signed jwt as the bearer token without having to go through a two-step OAuth process.

I've got stuff to sign a jwt but still getting authentication errors trying to call the raw api just with curl (as a first step) via something like

curl -H "Authorization: Bearer my_signed_jwt" https://www.googleapis.com/bigquery/v2/projects/my_project_id/datasets

("Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential."

Does anyone have an example of doing this? Might be missing just a simple thing that a working example would make obvious.

thanks

Upvotes: 0

Views: 657

Answers (2)

user655489
user655489

Reputation: 1326

ok - the trick as to my original question had to do with getting an access token for use in the api call.

const { JWT } = require('google-auth-library');
function getJWTResultWithAccessAndRefreshToken(jsonObjectFromGoogleKeyEtcFile,
                                                callbackWithErrAndResult) {

var scopes = [
              "https://www.googleapis.com/auth/bigquery",
              "https://www.googleapis.com/auth/cloud-platform",
              "https://www.googleapis.com/auth/devstorage.full_control",
              "https://www.googleapis.com/auth/devstorage.read_only",
              "https://www.googleapis.com/auth/devstorage.read_write"
            ];

var jwt = new JWT(
    jsonObjectFromGoogleKeyEtcFile.client_email,
    null,
    jsonObjectFromGoogleKeyEtcFile.private_key,
    scopes);

jwt.authorize(function (err, result) {
    callbackWithErrAndResult(err, result.access_token, result.refresh_token);
});

}

Here, jsonObjectFromGoogleKeyEtcFile is the json object from the json file you get when you generate "Service account keys"/Credentials in the Google Cloud Platform APIs & Services page.

The access_token generated can be used to make a call like below - which worked - where I used the access_token from the function above, and got the projectId from the project_id property of jsonObjectFromGoogleKeyEtcFile:

curl -H "Authorization: Bearer generated_via_jwt_access_token" \                    
          https://www.googleapis.com/bigquery/v2/projects/projectId/datasets

Interestingly, you get a refresh_token, too, but it has value "jwt-placeholder"

Whew.

Upvotes: 0

Tamir Klein
Tamir Klein

Reputation: 3642

You can use this working example which does

  1. Init query object
  2. Init oAuth2 object
  3. Call bigQuery.Jobs.insert

if (!global._babelPolyfill) {
    var a = require("babel-polyfill")
}

import {google} from 'googleapis'

let bigQuery = google.bigquery("v2")

describe('Check API', async () => {

    it('Test query', async () => {
        let result = await test('panada')

    })

    async function test(p1) {
        try {
            let query = `SELECT url FROM \`publicdata.samples.github_nested\`
                WHERE repository.owner = 'panada'`

            let auth = getBasicAuthObj()
            auth.setCredentials({
                access_token: "myAccessToken",
                refresh_token: "myRefreshToken"
            })

            let request = {
                "projectId": "myProject",
                auth,
                "resource": {
                    "projectId": "myProject",
                    "configuration": {
                        "query": {
                            query,
                            "useLegacySql": false
                        },
                        "dryRun": false
                    }
                }
            }

            console.log(`query is: ${query}`)

            let result = await callBQ(request) //Check JOB status to make sure it's done
            console.log(`result is: ${JSON.stringify(result.data)}`)

            result.forEach((row, index) => {
                console.log(`row number ${index}, url is: ${row.url}`)
            })
        } catch (err) {
            console.log("err", err)
        }
    }

    /**
     * Call BigQuery jobs.insert
     * @param request
     * @returns {Promise}
     */
    async function callBQ(request) {
        debugger
        console.log("request", request)
        try {
            let result = await bigQuery.jobs.insert(request, request)//, (err, results) => {
            console.log(`All good.....`)

            return result
        } catch (e) {
            console.log(`Failed to run query: ${e}`)
        }

    }


    /**
     * Create oAuth object
     * @returns {OAuth2Client}
     */
    function getBasicAuthObj() {
        let clientId = 'myClientId'
        let clientSecret = 'mySecret'
        let redirectUrl = 'url'

        return new google.auth.OAuth2(
            clientId,
            clientSecret,
            redirectUrl
        )
    }
})

note: You need to add this line to your package.json

"googleapis": "34.0.0"

Upvotes: 1

Related Questions