Reputation: 63
I'm trying to connect to the Google Drive API with a NodeJS server using a service account. The goal is for the server to be able to authenticate as the service account, retrieve relevant files from a drive, and send them back to the user, without the user needing to log in to Google directly. This would allow me to control file access through my web app instead of having to manually share and unshare files through Drive. From my understanding of the Google Drive API, this should all be possible. The problem is that I can't even figure out how to authenticate my server. The server runs on an AWS EC2 instance. To clarify, I do not want the user to have to authenticate using the frontend interface.
I've followed the quickstart guide and set up a service account & key as instructed here, but upon creating the key as instructed in the second link, it doesn't look like I have the correct credentials.json
file. The JSON file I get after generating a key on the Google Developer Console has the following object keys (values intentionally removed):
type
, project_id
, private_key_id
, private_key
, client_email
, client_id
, auth_uri
, token_uri
, auth_provider_x509_cert_url
, client_x509_cert_url
The quickstart guide suggests that this file should contain client_secret
and redirect_uris
within some installed
object (const {client_secret, client_id, redirect_uris} = credentials.installed;
):
Attempting to run this index.js
quickstart file causes an error to be thrown, since installed
does not exist within credentials.json
. Where can I generate the necessary credentials file? Or am I on the wrong track completely?
Posts like this reference a similar issue on an older version of the quickstart documentation, but the solutions here don't help since there isn't a client_secret
key in my credentials file.
Upvotes: 2
Views: 6419
Reputation: 11
In case anyone else spent too much time working out how to authenticate with a service account, this is how I got uploading a file to work:
const { google } = require('googleapis');
const drive = google.drive('v3');
const auth = new google.auth.GoogleAuth({
credentials: {
client_email: process.env.CLIENT_EMAIL,
client_id: process.env.CLIENT_ID,
private_key: process.env.PRIVATE_KEY,
},
scopes: [
'https://www.googleapis.com/auth/drive',
],
});
async function handler(req, res) {
const authClient = await auth.getClient();
google.options({ auth: authClient });
try {
await drive.files.create({
requestBody: {
name: 'Test',
mimeType: 'text/plain',
parents: [FOLDER_ID], // make sure to share the folder with your service account
},
media: {
mimeType: 'text/plain',
body: 'Hello World',
},
});
} catch (error) {
return res.status(500).json({ error: `Error adding row. ${error.message}` });
}
return res.status(201).json({ message: 'Done' });
}
export default handler;
Upvotes: 1
Reputation: 201378
When I saw the showing keys of your credentials.json
file, I understood that the file is the credential file of the service account. If my understanding is correct, when I saw your showing script, it seems that the script is for OAuth2. In this case, this script cannot be used for the service account. I thought that this is the reason for your current issue.
In order to use Drive API using the service account, how about the following sample script?
Before you use this script, please set credentialFilename
of the service account. In this case, please include the path.
const { google } = require("googleapis");
const credentialFilename = "credentials.json";
const scopes = ["https://www.googleapis.com/auth/drive.metadata.readonly"];
const auth = new google.auth.GoogleAuth({keyFile: credentialFilename, scopes: scopes});
const drive = google.drive({ version: "v3", auth });
// This is a simple sample script for retrieving the file list.
drive.files.list(
{
pageSize: 10,
fields: "nextPageToken, files(id, name)",
},
(err, res) => {
if (err) return console.log("The API returned an error: " + err);
const files = res.data.files;
console.log(files);
}
);
https://www.googleapis.com/auth/drive.metadata.readonly
as the scope. Please modify this for your actual situation.Upvotes: 7