I'm attempting to build an email parser that responds to a gmail pubsub message. I am currently able to receive and parse the pubsub message and extract the historyId, but I'm having trouble authenticating my request to the gmail api. Here's what I have up to now:
//function defined outside the scope of the main function
//used to create auth client
function getAuthClient(event, callback) {
var GoogleAuth = require('google-auth-library');
var authFactory = new GoogleAuth();
authFactory.getApplicationDefault(function (err, authClient) {
if (err) {
console.log('Unable to get application default credentials.');
callback(err);
return;
}
// Create the oAuth scopes you need
if (authClient.createScopedRequired && authClient.createScopedRequired()) {
console.log('creating scoped client');
authClient = authClient.createScoped([
'https://mail.google.com/'
]);
}
callback(null, authClient);
});
}
exports.gmailParser = function gmailParser (event, callback) {
var path = require('path');
var base64 = require('base-64');
// Set your service account key file into the environment for the auth lib
to pick up
process.env['GOOGLE_APPLICATION_CREDENTIALS'] = path.resolve(__dirname,
'auth_credentials.json');
console.log(process.env['GOOGLE_APPLICATION_CREDENTIALS']);
console.log(__dirname);
//parse pubsub message
var pubsubMessage = event.data;
var baseMessage = pubsubMessage.data;
var decodedMessage = base64.decode(baseMessage);
var messageJSON = JSON.parse(decodedMessage);
// Extract emailAddress and historyId from gmail pubsub message
var historyId = messageJSON.historyId;
var email = messageJSON.emailAddress;
getAuthClient(null, function(err, authClient) {
//import necessary libraries
var google = require('googleapis');
var gmail = google.gmail('v1');
if(err) {
callback(err);
}
// Construct a params object
var params = {
userId: email,
startHistoryId: historyId
};
//Attempt to call gmail api. This is where the error occurs.
gmail.users.history.list(params, function(error, response) {
if (error) {
console.log('Encountered error', error);
callback(error);
} else {
console.log('Response', response);
callback(response);
}
});
});
};
The code runs successfully but I get the following error:
"Error: Login Required
at Request._callback (/user_code/node_modules/googleapis/node_modules/google-auth-library/lib/transporters.js:85:15)
at Request.self.callback (/user_code/node_modules/googleapis/node_modules/request/request.js:188:22)
at emitTwo (events.js:106:13)
at Request.emit (events.js:191:7)
at Request.<anonymous> (/user_code/node_modules/googleapis/node_modules/request/request.js:1171:10)
at emitOne (events.js:96:13)
at Request.emit (events.js:188:7)
at IncomingMessage.<anonymous> (/user_code/node_modules/googleapis/node_modules/request/request.js:1091:12)
at IncomingMessage.g (events.js:291:16)
at emitNone (events.js:91:20)"
I've tried adding the authClient to the param object but it returns a "Bad request" error. I've tried changing the order of the imports, created new credentials, but I haven't been able to get anywhere. If anyone has any pointers it would be greatly appreciated.
This blogpost might help. It has details regarding getting OAuth tokens using nodejs and Cloud Functions. I tried it and it worked fine.
https://cloud.google.com/blog/products/application-development/adding-custom-intelligence-to-gmail-with-serverless-on-gcp
Code: https://github.com/GoogleCloudPlatform/cloud-functions-gmail-nodejs
The below code snippet requests an OAuth 2.0 authorisation code
exports.oauth2init = (req, res) => {
// Define OAuth2 scopes
const scopes = [
'https://www.googleapis.com/auth/gmail.modify'
];
// Generate + redirect to OAuth2 consent form URL
const authUrl = oauth.client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
prompt: 'consent' // Required in order to receive a refresh token every time
});
return res.redirect(authUrl);
};
The below code snippet gets an access token from the OAuth authorisation code
exports.oauth2callback = (req, res) => {
// Get authorization code from request
const code = req.query.code;
// OAuth2: Exchange authorization code for access token
return new Promise((resolve, reject) => {
oauth.client.getToken(code, (err, token) =>
(err ? reject(err) : resolve(token))
);
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With