node.jsoauth-2.0jwtgoogle-fit

Can data be retrieved from the Google Fitness REST API using a JWT token to authenticate?


Apologies for my previous badly formulated question.

I am trying to write a standalone NodeJS app, that retrieves activity data from the Google Fit REST API and writes it locally as a json file. The app will run unattended on a headless raspberry pi, so there are no "browser pop-up" windows in order to authenticate with a Google account.

I activated my Google Fit API and created service account credentials. My key is stored as MY_KEY.json in this example. Now using the googleapis library, I create a JWT token signed with MY_KEY.json, and authenticate with it when sending my request.

I get a response from the API, but the data is empty. (I know there is data, since doing a similar request in a browser with a traditional oauth2 flow returns all my activity data sessions. I wonder if authentication with JWT tokens using a service account is allowed for fitness data ?

Here is my code :

'use strict';

const {google, fitness_v1} = require('googleapis');
const path = require('path');
const fs = require('fs');

async function runSample() {
  // Create a new JWT client using the key file downloaded from the Google Developer Console
  const auth = new google.auth.GoogleAuth({
    keyFile: path.join(__dirname, 'MY_KEY.json'),
    scopes: 'https://www.googleapis.com/auth/fitness.activity.read',
  });
  const client = await auth.getClient();

  // Obtain a new fitness client, making sure you pass along the auth client
  const fitness_v1 = google.fitness({
    version: 'v1',
    auth: client
  });
  //console.log(client);

  const res = await fitness_v1.users.sessions.list({
    "userId": "me"
  });

  fs.writeFile('session.json', JSON.stringify(res.data, null, 4), (err) => {
    if (err) {
        throw err;
    }
    console.log("Retrieved sessions are saved as JSON.");
  });

  console.log(res.data);

  return res.data;
  
}

if (module === require.main) {
  runSample().catch(console.error);
}

// Exports for unit testing purposes
module.exports = {runSample};

The response is :

{
  session: [],
  deletedSession: [],
  nextPageToken: 'XmRh96blablablan4yFjZQ'
}

It should be :

{
  "session": [
    {
      "id": "healthkit-D7B3AC93-3739-4E04-978A-C53599D8401E",
      "name": "Uni",
      "description": "",
      "startTimeMillis": "1645651234280",
      "endTimeMillis": "1645676584280",
      "modifiedTimeMillis": "1645676989684",
      "application": {
        "packageName": "com.apple.workout",
        "version": "",
        "detailsUrl": ""
      },
      "activityType": 72
    },
    {
      "id": "healthkit-3691B45B-9D51-4C14-ACC6-EC9DB48B5F23",
      "name": "Juoksu",
      "description": "",
      "startTimeMillis": "1647073527249",
      "endTimeMillis": "1647075778248",
      "modifiedTimeMillis": "1647076769108",
      "application": {
        "packageName": "runkeeperpro",
        "version": "",
        "detailsUrl": ""
      },
      "activityType": 56
    }
  ],
  "deletedSession": [],
  "nextPageToken": "XmRh96blablablan4yFjZQ"
}

Any suggestions ? Thanks in advance.


Solution

  • According to Addendum: Service account authorization without OAuth:

    With some Google APIs, you can make authorized API calls using a signed JWT directly as a bearer token, rather than an OAuth 2.0 access token. (snip)

    If the API you want to call has a service definition published in the Google APIs GitHub repository, you can make authorized API calls using a JWT instead of an access token.

    There is no such service definition for Fit, so, unfortunately, the answer is that you can't use JWT.