I am trying to return the value of the data object from the function listLabels in my code below. I would like to have it be accessed from an Express endpoint, e.g. (localhost:3001).
I have been able to console log the object and I have been able to send myself emails. Any help in returning the value when accessing the Express endpoint would be greatly appreciated.
const express = require('express')
const app = express()
const fs = require('fs')
const readline = require('readline')
const {google} = require('googleapis')
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'application/json')
let data = getLabels()
console.log('data: ' + data)
res.json(data)
})
app.get('/hello', function (req, res) {
res.send('hello there')
})
app.listen(3001, () => console.log('server up on 3001'))
const SCOPES = ['https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.send'
];
const TOKEN_PATH = 'credentials.json';
function getLabels() {
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
authorize(JSON.parse(content), listLabels);
});
}
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
fs.writeFile('getCredentials.txt', authUrl, (err) => {
if (err) throw err;
console.log('getCredentials.txt saved!')
})
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return callback(err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function listLabels(auth) {
const gmail = google.gmail({version: 'v1', auth});
console.log('here')
gmail.users.messages.list({
userId: 'me',
maxResults: 10
}, (err, {data}) => {
if (err) return console.log('The API returned an error: ' + err);
console.log('data in listlabels ' + JSON.stringify(data))
//return data
let dataForExpress
messages.forEach(function (message, index) {
gmail.users.messages.get({
userId: 'me',
id: data.messages[index].id,
format: 'raw'
}, (err, {data}) => {
if (err) return console.log('Error: ' + err)
console.log(data)
dataForExpress.push(data)
});
})
return dataForExpress
})
}
The data you are expecting is coming back in an asynchronous fashion, so you will need to handle it asynchronously using either callbacks or async await.
Here is an example using callbacks.
const express = require('express')
const app = express()
const fs = require('fs')
const readline = require('readline')
const {google} = require('googleapis')
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'application/json')
// let data = getLabels()
getLabels((labels) => {
console.log(labels)
res.json(labels)
})
//console.log('data: ' + data)
//res.json(data)
})
app.get('/hello', function (req, res) {
res.send('hello there')
})
app.listen(3001, () => console.log('server up on 3001'))
const SCOPES = ['https://mail.google.com/',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.send'
];
const TOKEN_PATH = 'credentials.json';
function getLabels(callback) {
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// so here, instead of passing it listLabels directly, we will pass it just a regular callback, and call listlabels inside that callback. This way we can choose what to do with listlabels return value.
authorize(JSON.parse(content), (auth) => {
listLabels(auth, (listOfLabels) => {
console.log(listOfLabels) // we should have the list here
callback(listOfLabels)
}) //match the original arguments
});
});
}
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
fs.writeFile('getCredentials.txt', authUrl, (err) => {
if (err) throw err;
console.log('getCredentials.txt saved!')
})
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return callback(err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function listLabels(auth, callback) {
const gmail = google.gmail({version: 'v1', auth});
console.log('here')
gmail.users.messages.list({
userId: 'me',
maxResults: 10
}, (err, {data}) => {
if (err) return console.log('The API returned an error: ' + err);
console.log('data in listlabels ' + JSON.stringify(data))
//return data
let dataForExpress
let messages = data.messages
messages.forEach(function (message, index) {
console.log("Inside foreach, message and index :", message, index)
gmail.users.messages.get({
userId: 'me',
id: message.id,
format: 'raw'
}, (err, {data}) => {
if (err) return console.log('Error: ' + err)
console.log(data)
dataForExpress.push(data)
if dataForExpress.length == messages.length { // we done
callback(dataForExpress)
}
});
})
})
}
Related
Is this the right way to access the google calendar api using a refresh token? That's 2 weeks after a user gave me his consent.
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_OAUTH_CLIENT_ID,
process.env.GOOGLE_OAUTH_CLIENT_SECRET,
process.env.DOMAIN_NAME + "/google/oauth/callback"
);
oauth2Client.setCredentials({
refresh_token: refreshToken
})
const calendar = google.calendar({version: "v3", auth: oauth2Client});
calendar.events.watch({
auth: oauth2Client,
resource: {
id: makeid(10) + Date.now(),
token: process.env.GOOGLE_API_WATCH_TOKEN,
type: 'web_hook',
address: "https://" + process.env.DOMAIN_NAME + "/google/notifications"
},
calendarId: "primary"
}, function(error, response) {
if (error) {
defer.reject(error);
} else {
defer.resolve(response);
}
});
return defer.promise;
I'm not using jwt.
Your code shows a valid approach to token handling if it doesn't generate any issues. As an answer, I show below an alternative to OAuth 2.0 token handling.
This code will first read the token file with the readFile method. Then it will be fed to the authorize function. That function will set up the objects used on the authentication flow, and if it fails (due to an invalid token, per example) then it will call the getAccessToken function to gather new tokens.
const fs = require('fs');
const readline = require('readline');
const {
google
} = require('googleapis');
const SCOPES = ['{YOUR SCOPES HERE}'];
const TOKEN_PATH = 'token.json';
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
authorize(JSON.parse(content), listEvents);
});
function authorize(credentials, callback) {
const {
client_secret,
client_id,
redirect_uris
} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getAccessToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token',
err);
oAuth2Client.setCredentials(token);
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
Please write back if you have doubts about this approach or your own.
Okay I am trying on gmail API ? It is driving me crazy, I am kind of new too it. First of all I want to print JSON response of Email and Labels to Browser or postman. Second Everytime I call API i have to reauthenticate.
any help would be really appreacited. what can I do in order to get to print response in browser which I am getting in console.
const { google } = require('googleapis');
const express = require('express');
const OAuth2Data = require('./credentials.json');
const fs = require('fs');
const { response } = require('express');
const app = express()
const TOKEN_PATH = 'token.json';
const CLIENT_ID = OAuth2Data.client.id;
const CLIENT_SECRET = OAuth2Data.client.secret;
const REDIRECT_URL = OAuth2Data.client.redirect_uris;
const oAuth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL)
var authed = false;
app.get('/', (req, res) => {
if (!authed) {
// Generate an OAuth URL and redirect there
const url = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: 'https://mail.google.com/'
});
console.log(url)
res.redirect(url);
} else {
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client });
gmail.users.labels.list({
userId: 'me',
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const labels = res.data.labels;
if (labels.length) {
console.log('Labels:');
labels.forEach((label) => {
console.log(`- ${label.name}`);
});
} else {
console.log('No labels found.');
}
});
res.send('Logged in')
}
})
app.get('/auth/google/callback', function (req, res) {
const code = req.query.code
if (code) {
// Get an access token based on our OAuth code
oAuth2Client.getToken(code, function (err, token) {
if (err) {
console.log('Error authenticating')
console.log(err);
} else {
console.log('Successfully authenticated');
oAuth2Client.setCredentials(token);
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
authed = true;
res.redirect('/')
}
});
}
});
const port = process.env.port || 5000
app.listen(port, () => console.log(`Server running at ${port}`));
app.get('/m',(req, res) => {
if (!authed) {
// Generate an OAuth URL and redirect there
const url = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: 'https://mail.google.com/'
});
console.log(url)
res.redirect(url);
}
else {
const gmail1 = google.gmail({ version: 'v1', auth: oAuth2Client });
gmail1.users.messages.list({userId: 'me', maxResults: 2}, function (err, res) {
if (err) {
console.log('The API returned an error 1: ' + err);
return;
}
// Get the message id which we will need to retreive tha actual message next.
for (let index = 0; index < 2; index++) {
var message_id = res['data']['messages'][index]['id'];
gmail1.users.messages.get({auth:oAuth2Client, userId: 'me', 'id': message_id}, function(err, res) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
console.log('data',res['data']);
});
}
// Retreive the actual message using the message id
});
}
})
I am using a combination of the examples provided to download a document to my filesystem, in the future directly to the server but that's the next step.
The code runs without errors but the worksheet created has 0 bytes and cannot be opened. Any ideas please? The documentation is giving me analysis paralysis.
I have consulted countless github posts and questions here but nothing seems to stick.
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
// If modifying these scopes, delete credentials.json.
const SCOPES = ['https://www.googleapis.com/auth/drive'];
const TOKEN_PATH = 'token.json';
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* #param {Object} credentials The authorization client credentials.
* #param {function} callback The callback to call with the authorized client.
*/
function authorize(credentials, callback) {
const {
client_secret,
client_id,
redirect_uris
} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* #param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* #param {getEventsCallback} callback The callback for the authorized client.
*/
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error while trying to retrieve access token', err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Sheets API.
authorize(JSON.parse(content), grabFileFromDrive);
});
function grabFileFromDrive(auth) {
const drive = google.drive({
version: 'v3',
auth
});
var fileId = '<FILEIDHERE>';
var dest = fs.createWriteStream('/tmp/feedback-list.xlsx');
drive.files.export({
fileId: fileId,
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}, {
responseType: 'stream'
}), function(err, res){
res.data
.on('end', () => {
console.log('Done');
})
.on('error', err => {
console.log('Error', err);
})
.pipe(dest);
console.log(res);}
}
The document downloaded is corrupt/incorrectly formatted and has a 0 size value, how can I get a working excel sheet downloaded to my directory?
UPDATE: I have added working code below, I think the issue was token related and not being able to view the error produced within the downloaded document alerting me to insufficient scopes, either that or the response function wasn't in the right place, rebuilt it all again from documentation and a tutorial and somehow this works now. Hope it helps
const fs = require('fs');
const readline = require('readline');
const {
google
} = require('googleapis');
// If modifying these scopes, delete token.json.
const SCOPES = 'https://www.googleapis.com/auth/drive';
const TOKEN_PATH = 'token.json';
// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Drive API.
authorize(JSON.parse(content), downloadDriveFile);
});
function authorize(credentials, callback) {
const {
client_secret,
client_id,
redirect_uris
} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getAccessToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function downloadDriveFile(auth) {
const drive = google.drive({
version: 'v3',
auth
});
var fileId = 'xxxxxxxxxxxxxxx';
var dest = fs.createWriteStream('/tmp/feedback.csv');
// example code here
drive.files.export({
fileId: fileId,
mimeType: 'text/csv'
// excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
}, {
responseType: 'stream'
},
function (err, res) {
res.data
.on('end', () => {
console.log('Done');
})
.on('error', err => {
console.log('Error', err);
})
.pipe(dest);
})
///
}
I am trying to create a client-side script that allows someone to login to their Google Account and then access a Firestore database once they are authenticated. Everything works except for some reason after signing in using firebase.auth it isn't passing this data to firebase.firestore to say they are authenticated.
Here is the script that I am using, the only part that is failing is when I am trying to add to a Firestore collection.
const firebase = require ("firebase/app");
require("firebase/auth");
require("firebase/firestore");
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
const util = require('util')
var config = {
**HIDDEN**
};
firebase.initializeApp(config);
const SCOPES = ['email','profile'];
const TOKEN_PATH = 'token.json';
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Gmail API.
authorize(JSON.parse(content), listLabels);
});
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function listLabels(auth) {
var credential = firebase.auth.GoogleAuthProvider.credential(auth.credentials.id_token);
firebase.auth().signInAndRetrieveDataWithCredential(credential).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
var email = error.email;
var credential = error.credential;
console.log(errorCode);
console.log(errorMessage);
});
var firestore = firebase.firestore();
firestore.settings({
timestampsInSnapshots: true
});
firestore.collection("users").add({
test: "Hello"
});
firebase.auth().signOut();
}
And below is my rules for the database, if I change it to just if true; it works perfectly fine. But I want to make sure only an authenticated user can access that database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
The method signInAndRetrieveDataWithCredential returns a promise, and you aren't waiting for it to finish before accessing the data on Firestore, so that is probably what is causing the issues. I believe this might work:
function listLabels(auth) {
var credential = firebase.auth.GoogleAuthProvider.credential(auth.credentials.id_token);
firebase.auth().signInAndRetrieveDataWithCredential(credential)
.then(user => {
var firestore = firebase.firestore();
firestore.settings({
timestampsInSnapshots: true
});
firestore.collection("users").add({
test: "Hello"
});
firebase.auth().signOut();
})
.catch(function (error) {
var errorCode = error.code;
var errorMessage = error.message;
var email = error.email;
var credential = error.credential;
console.log(errorCode);
console.log(errorMessage);
});
}
I am a beginner in Node JS and I want to upload a local file to google drive. I have followed the instructions from this URL. But when I am going to run it, It gives an error like "insufficient permissions." Please help me out what I am missing in it.
Here is my code.
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
const OAuth2Client = google.auth.OAuth2;
const SCOPES = ['https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.files.create',
'https://www.googleapis.com/auth/spreadsheets'];
const TOKEN_PATH = 'credentials.json';
// Load client secrets from a local file.
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Sheets API.
authorize(JSON.parse(content), real_upload_files);
});
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new OAuth2Client(client_id, client_secret, redirect_uris[0]);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);});
}
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return callback(err);
oAuth2Client.setCredentials(token);
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function real_upload_files(auth) {
var drive = google.drive('v3');
var fileMetadata = {
'name': 'Studentdata.xlsx',
'mimeType': 'application/vnd.google-apps.spreadsheet'
};
var media = {
mimeType: 'text/csv',
body: fs.createReadStream('files/students.xlsx')
};
drive.files.create({
resource: fileMetadata,
media: media,
auth: auth,
fields: 'id',
}, function(err, file) {
if (err) {
console.log(err);
} else {
console.log('File Id: ', file.id);
}
});
}
Please help me out what I am missing in it. Looking forward.
What's happening here is that you're following the NodeJS Quickstart which uses the drive.files.list method which only uses the default 'read-only' scope:
https://www.googleapis.com/auth/drive.metadata.readonly
Now you modified the sample and decided to use upload method using files.create. Your default scopes won't work anymore because it's for 'read-only' (you're doing a 'write' command). You need to use the scopes mentioned in the files.create method, at least one of these:
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
After that, delete your previously saved credentials (somewhere in your directory where credentials are stored) for this project and re-do the authorization. This should work after that.