Search code examples
node.jsgoogle-apigoogle-drive-apiservice-accountsgoogle-api-nodejs-client

Google Drive API - Invalid service account credentials


I am learning to use the Google Drive API and started with a small script isloated away from anything:

import * as fs from "fs";
import * as gdrive from "@googleapis/drive";

const auth = new gdrive.auth.GoogleAuth({
    keyFile: "creds.json",
    scopes: [ "https://www.googleapis.com/auth/drive" ]
});

const ds = gdrive.drive({ version: "v3", auth });

const meta = {
    "name": "uploadme.csv",
    "parents": [ "XXX" ] // Folder ID
};

const body = {
    mimeType: "text/csv",
    body = fs.createReadStream("uploadme.csv")
};

async function yeet() {
    const res = await ds.files.create({
        requestBody: meta,
        media: body
    });
    console.log(res);
}
yeet();

This small script works (returned a status 200 and I see the file uploaded to the folder I specified) and I moved on to integrating it with my main project, mostly directly copying the small script in. The only difference is a different folder structure and a different call stack, where in the small example I had it all in the project root while the main project had a more complex layout and program flow (a Discord bot responding to a command). Unexpectedly, it is giving an authentication error even though (as far as I'm aware) all I meaningfully changed was the project layout.

The small starter script still worked as it did during earlier testing, and even more confusingly, on the main project it's now telling me my key is bad, despite being the exact same auth code and key file I used earlier. Looking around, I see it might be my key has expired and I'm supposed to look for a refresh token, yet I'm unable to find where it is or how to use it when I do find it.

Could someone please point me in the right direction?

Thank you for your time.

Note: I'm using a service account key to access the APIs, not an OAuth credentials


Edit 1:

I ended up copying the entire testing script (still isolated from the main project though) and moved it to the main project's directory, and sure enough, it still worked. Now I'm really bamboozled as to what's going on.

Edit 2:

I linked up the small script with the main project by stubbing out the function and replacing it with a call to the test script (slightly modified by wrapping it in an exported function so it's callable as a module from the main project), and it still works. It's as if the key is locked into the test script.

Edit 3:

I've now swapped the problematic file in the main project for the working testing script, including the file name, and now it works. Very bizzare, but I am now no longer getting the 401 invalid credentials errors. I still don't know what was wrong with the original file in the main project, though.


Solution

  • Invalid service account credentials

    Normally means that the key fine you are using is invalid. You need to create a service account key file.

    If you open the json key file it should look something like this

    {
      "type": "service_account",
      "project_id": "Redacted-305109",
      "private_key_id": "Redacted",
      "private_key": "-----BEGIN PRIVATE KEY-----Redacted---END PRIVATE KEY-----\n",
      "client_email": "[email protected]",
      "client_id": "Redacted",
      "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/Redacted-305109.iam.gserviceaccount.com"
    }
    

    how to create a service account key file

    Docs: google-api-nodejs-client#service-account-credentials

    const {google} = require('googleapis');
    
    const auth = new google.auth.GoogleAuth({
      keyFile: '/path/to/your-secret-key.json',
      scopes: ['https://www.googleapis.com/auth/cloud-platform'],
    });