nodejs gmail failedPrecondition - node.js

so i am using this: https://github.com/google/google-api-nodejs-client#using-api-keys
here is the nodejs code:
router.get("/deals", function(req, res, next) {
var key = require('../gmail-a574e06ad196.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/gmail.readonly', 'https://mail.google.com/'], // an array of auth scopes
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
res.send('123');
return;
}
console.log('token is: ', tokens)
// Make an authorized request to list Drive files.
drive.users.labels.list({
auth: jwtClient,
userId: 'me'
}, function (err, resp) {
console.log(err)
res.send('123')
});
});
});
but once i hit that api, i got the following error:
errors:
[ { domain: 'global',
reason: 'failedPrecondition',
message: 'Bad Request' } ] }
I google around. found on some sites that said, the service account only work if you have G-Suite account, which is a paid account. My gmail account is a normal personal account. so no matter what i do, it just wont work?
Is that true?
What i am trying to do is, so i have a gmail account to collects newsletters, I want to create a nodejs api that returns/lists all emails from that account. I dont want oAuth, because really, no need to manually login. All i want is when page load, login automaically happens and the api returns list of emails, so everyone can see the list. Is there any other appoach of achieving this?
Thanks

you can not use service account with a normal users Gmail account due to the fact that there is no way to delicate access to another user. you can only do it with gsuite.
you could consider going through the SMTP or IMAP server's directly

Related

How to use azure AD authentication from node.js server side non interactively

I have configured azure AD service and an user in it and used react-adal to get the token, which worked fine.But now i need to change this flow and instead have my own login form and send the credentials to node.js express server and verify these from azure ad without a login popup from azure and store the returned token in the passport session.I have tried using node-adal but not sure how this can be achieved ,Can this be done? Are there any examples for this.Thanks
Agree with #juunas, here is the non-interactive method(login with username and password) for your reference. This sample is used to manage MicrosoftGraph Resources.
var msRestAzure = require('ms-rest-azure');
var graphRbacManagementClient = require('azure-graph');
var tenantId='abcd-efgh-ijk-lmno-12345';
// Enter your tenant ID here which can be found from your Azure AD URL
// Eg. https://manage.windowsazure.com/example.com#Workspaces/ActiveDirectoryExtension/Directory/<TenantId>/users
msRestAzure.loginWithUsernamePassword('username#contosocorp.onmicrosoft.com', 'your-password', { tokenAudience: 'graph', domain: tenantId }, function (err, credentials, subscriptions) {
if (err) console.log(err);
var client = new graphRbacManagementClient(credentials, tenantId);
var userParams = {
accountEnabled: true,
userPrincipalName: 'OfficialStark#<yourdomain.com>', //please add your domain over here
displayName: 'Jon Snow',
mailNickname: 'OfficialStark',
passwordProfile: {
password: 'WinterisComing!',
forceChangePasswordNextLogin: false
}
};
client.users.create(userParams, function (err, user, request, response) {
if (err) return console.log(err);
console.log(user);
var userObjectId = user.objectId;
client.users.list(function (err, result, request, response) {
if (err) return console.log(err);
console.log(result);
client.users.deleteMethod(userObjectId, function (err, result, request, response) {
if (err) return console.log(err);
console.log(result);
});
});
});
});
There is a way, but you should not use it.
When using federated authentication, you should not be handling passwords.
The one way that works is a legacy migration path, named the ROPC flow.
However, none of these will work:
User with MFA
User synced from on-prem AD
User with expired password
If you want to do something as the user in the background, have them login and store their refresh token securely.
You'd need to exchange the front-end access token for a back-end access token + refresh token.
Then you can use the refresh token to get new tokens for the user whenever.
Alternatively you can require application permissions to APIs and access them using client credentials from your API (client id + secret/certificate).

How to know authenticated email of an user who authenticated with his google account for my app

I am integrating google authentication for my app for creating calender events.
const {google} = require('googleapis');
const SCOPES = ['https://www.googleapis.com/auth/calendar','https://www.googleapis.com/auth/userinfo.email']
I have used the above scopes in authentication and generated the url and sent to the client. Authentication got success and i am able to receive code and generating token.
But with the code, I need the authenticated user's email, whoever signed in. Is there any way/example to know how to get user's email?. I searched in google for finding solution. But i didn't get that. Help me to know about this.
After you have received the token, you need to make a HTTP request to the userinfo endpoint using that token to get the required user info.
You can get the url for that endpoint from the discovery document which can be found at https://accounts.google.com/.well-known/openid-configuration.
The current url to get user info is https://openidconnect.googleapis.com/v1/userinfo.
If you do a calendar get on the users primary calendar. All users have a primary calendar
request
GET https://www.googleapis.com/calendar/v3/calendars/primary
response
{
"kind": "calendar#calendar",
"etag": "\"JWPyaEfg9X1jMhlHCcI4tl2h6uo/AxePbI13h8-KuIOLek\"",
"id": "xxxx#gmail.com",
"summary": "xxx#gmail.com",
"timeZone": "Europe/Copenhagen",
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"eventHangout"
]
}
}
Both Id and summary will be the users email address. By doing it this way you will not need to request the https://www.googleapis.com/auth/userinfo.email scope
Node guesss
Note: I am not a node.js developer this is a wild guess you will have to work this out
function listEvents(auth) {
const calendar = google.calendar({version: 'v3', auth});
calendar.about.get({
calendarId: 'primary'
}, (err, res) => {
if (err) return console.log('The API returned an error: ' + err);
const results = res;
if (results ) {
console.log(results.id);
} else {
console.log('No upcoming events found.');
}
});

How to refresh access token for Google Analytics Reporting API v3

So I am working on a Node.js app that will poll Google Analytics api ever x amount of seconds. I have setup a "Service Account", and converted the p12 key to a .pem file. Initial setup looks something like this:
var authClient = new google.auth.JWT(authData.serviceEmail, authData.keyFile, null, authData.scope, '');
authClient.authorize(function(err, tokens) {
if (err) {
winston.log('error', 'Error authorizing with GA', {error: err});
return;
}
setInterval(function() {
analytics.data.realtime.get({
'auth': authClient,
...
}, function (err, body) {
// getting 401 error here
})
}, 20000);
});
I had not realized that the initial tokens have an expiration date of 1 hour; however the tokens I receive look like this:
{
access_token: ...,
token_type: 'Bearer',
expiry_date: NaN,
refresh_token: 'jwt-placeholder
}
My question is, once I get that 401 invalidCredentials error, do I simply just re-authorize to get a new access token to be able to poll from Google Analytics? I am new to JWT, and this seems like it will be authorizing way too many times. Is there a limit to this?
For reference, I am using the Google API Node.js Client Library
Yes, just rebuild authClient as you did the first time. Service Accounts don't have refresh tokens like other OAuth flows, you just rebuild the authentication when the current access token expires.

Does the Gmail API support JWT?

I want to access the Gmail API using NodeJS.
I'm using a server-to-server approach (see this) but when I execute the code below, I get a backEndError, code 500 from the Google API.
Any ideas?
var authClient = new google.auth.JWT(
'email',
'key.pem',
// Contents of private_key.pem if you want to load the pem file yourself
// (do not use the path parameter above if using this param)
'key',
// Scopes can be specified either as an array or as a single, space-delimited string
['https://www.googleapis.com/auth/gmail.readonly']
);
authClient.authorize(function(err, tokens) {
if (err)
console.log(err);
gmail.users.messages.list({ userId: 'me', auth: authClient }, function(err, resp) {
// handle err and response
if (err) {
console.log(err);
});
Yes, I have the same problem. If I use the scope "https://mail.google.com", I get
403
{
"error" : "access_denied",
"error_description" : "Requested client not authorized."
}
And if I use the scope "https://mail.google.com/" (notice the / at the end), I get
403
'Forbidden'
It seems to be related to using JWT and service account.

Google Play Android Developer API 401 Insufficient permissions

I'm using Google Play Android Developer API to server to server check subscription status of our users' subscriptions but after successful authorization and asking for an existing subscription I get the 401 response with the following message 'The current user has insufficient permissions to perform the requsted operation'.
Visiting https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=XXXXXX I can see that I do have the requested scope (https://www.googleapis.com/auth/androidpublisher) but I still get the same response everytime.
Did anyone else have the same problem?
Edit: I've seen what the Explore API app does, it adds the key in the query string of a request but I don't have that value. In the console I've created a Service Account Client Id which has a client id, email address and a private key but there is no API key which apparently Explore API uses.
Edit no. 2: I've added the service account generated email both to Google Play Developer Console and Google Wallet console but I still have no acces. I'm using nodejs and the google-oauth-jwt because there is not google provided lib for nodejs.
Here is the code I'm using to make a request:
var request = require('google-oauth-jwt').requestWithJWT();
function makeReq() {
request({
url: 'https://www.googleapis.com/androidpublisher/v1.1/applications/{packageName}/subscriptions/{subscriptionId}/purchases/{purchaseToken}',
jwt: {
// use the email address of the service account, as seen in the API console
email: 'blahblahtrutjtrutj#developer.gserviceaccount.com',
// use the PEM file we generated from the downloaded key
keyFile: 'purchases-test.pem',
// specify the scopes you wish to access
scopes: ['https://www.googleapis.com/auth/androidpublisher']
}
}, function (err, res, body) {
if (err) {
console.log(err);
} else {
console.log("BODY IS ------------------------------------------");
console.log(JSON.parse(body));
}
});
}
If your app is only released in a closed alpha track, you'll also have to add your service account's email address (client_email) to the License Testers at Settings -> Account detail in the Play Console.
There is an email address associated with your service account.
This needs to have appropriate permissions in both the dev console AND the Play store. Make sure to add the service address to the Play store.
The way I approached it was to use
var googleAuth = require('google-oauth-jwt'),
authObject = {
email: 'blahblahtrutjtrutj#developer.gserviceaccount.com',
keyFile: 'purchases-test.pem',
scopes: ['https://www.googleapis.com/auth/androidpublisher']
};
googleAuth.authenticate(authObject, function (err, token) {
next(err, token);
});
I store the token in redis for an hour and use that token to make my request to the store:
var opts = {
url : verifyUrl + payload.packageName + '/inapp/' + payload.productId + '/purchases/' + payload.token,
headers: {
authorization : 'Bearer ' + token
}
};
request.get(opts, function (error, response, body) {
next(error, response, body);
});

Resources