Google account gets suspended when using Gmail API from Node.js Nodemailer - javascript

I have an Express web application on a Node.js server. It supports sending email notifications for registration, password reset, etc. For this, I use Nodemailer and XOAuth2 to connect to Google API using a normal Google account. The connection works well and emails are being sent as expected. But after a while (1-3 days), Google sends me a message saying my account "has been suspended because of a violation of our Terms of Service" (screenshot). So I have to manually recover the account using the link in the notification and then the emails that were blocked during suspension are sent.
After getting 3 of those notifications, I noticed that they follow only if I triggered my email sending function (see below)
I tried to log XOAuth2's token refresh and seems like it works
I tried to renew the refreshToken from the playground several times but the problem remains
IMHO, it might be that I'm using a free account and Google wants me to pay for using its API, it thinks I do some kind spams, or it just doesn't want me to use its API. I'm I wrong?
So my questions are:
Why does my account get suspended?
What can I do to fix this problem?
Code details (approximate):
var bluebird = require('bluebird');
var nodemailer = require('nodemailer');
var xoauth2 = require('xoauth2');
// clientId, clientSecret taken from: https://console.developers.google.com/
// Create credentials > OAuth client ID > Web application >
// Name = Nodemailer,
// Authorised redirect URIs = https://developers.google.com/oauthplayground
//
// refreshToken taken from: https://developers.google.com/oauthplayground/
// Access token location: Autorization header w/ Bearer prefix
// Access type: Offline
// Force prompt: Consent Screen
// Use your own OAuth credentials: yes
// Authorized APIs: everything inside Gmail API v1
// Auto refresh the token after it expires: yes
xoauth2Gen = xoauth2.createXOAuth2Generator({
user: 'example#gmail.com', // my real google account
clientId: '84037...t.com', // my real clientId
clientSecret: 'c3Yo...KP', // my real clientSecret
refreshToken: '1/ex...Wk' // my real refreshToken
// nothing more here
});
var mail_transport: {
service: 'Gmail',
auth: { xoauth2: xoauth2Gen }
};
var mailer = bluebird.promisifyAll(nodemailer.createTransport(mail_transport));
mailer.sendMail({
from : '"Example User" <example#gmail.com>',
to : 'recipient#gmail.com',
subject : 'Example subject',
text : 'Example\nplain\ntext',
// could it be bad html?
html : 'Example<br><strong>html</strong><br>version'
}).then(function (info) { console.log(info); });

Related

endpoints_resolution_error in msal react

I was trying to acquire token from our Microsoft tenant. I have no knowledge about the Azure AD or whatsoever, because I only tasked to develop front end for our Microsoft Dynamics App in React. I only got some of the credential like tenant id, client id, client secret and resource.
I used MSAL Node library and function ConfidentialClientApplication() to acquire the token
But when I check it in the Ms. Edge's console log it throw an error
{"errorCode":"endpoints_resolution_error","errorMessage":"Error: could
not resolve endpoints. Please check network and try again. Detail:
ClientAuthError: openid_config_error: Could not retrieve endpoints.
Check your authority and verify the .well-known/openid-configuration
endpoint returns the required endpoints. Attempted to retrieve
endpoints from: verify
url","subError":"","name":"ClientAuthError","correlationId":""}
When I click the veryfy url (Cannot show you the url because it might contain sensitive information)
It shows all the metadata of the open id so I thought maybe it's normal.
But why is the error endpoints_resolution_error throwed when everything is normal?
Here is some snapshot of my code
const config = {
auth: {
clientId: clientID
authority: "https://login.microsoftonline.com/{tenantID}/",
clientSecret: clientSecret,
knownAuthorities: ["login.microsoftonline.com"],
protocolMode: "OIDC"
}
};
// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);
// With client credentials flows permissions need to be granted in the portal by a tenant administrator.
// The scope is always in the format "<resource>/.default"
const clientCredentialRequest = {
scopes: ["resource/.default"], // replace with your resource
};
cca.acquireTokenByClientCredential(clientCredentialRequest).then((response) => {
console.log("Response: ", response);
}).catch((error) => {
console.log(JSON.stringify(error));
});
I've tried changing the authority and the protocol mode several times, but same result

Firebase: how to send reset-link through email template sent from nodemailer?

I implemented sending emails via nodemailer.
Now when I create new user, that new user get "welcome email".
Problem is cus that "welcome email" should contain option for
resetting password.
How to add Firebase Resetting link in nodemailer email template?
This is my Email Template code for nodemailer
const output = `
<p>You have access to the Church Mutual Assignment Tool.</p>
<p>Follow this link to create new password for your account ${userRecord.email}:</p>
<a href="${resetPasswordLink}">
${resetPasswordLink}
</a>
<p>Thanks,</p>
<p>Your Church Mutual Assignment Tool team</p>
`
let message = {
from: 'nyik6nntutmq3vz6#ethereal.email',
to: `${user.email}`,
subject: 'Welcome to the Church Mutual Assignment Tool',
text: 'Plaintext version of the message',
html: output
}
This is my Nodemailer code:
var mailer = require('nodemailer')
var mailConfig = {
host: 'smtp.ethereal.email',
port: 587,
auth: {
user: 'nyik6nntutmq3vz6#ethereal.email',
pass: '3cbRjkZdPquDqA725s'
}
}
var transporter = mailer.createTransport(mailConfig)
module.exports = transporter
The Admin SDK now has some methods that allow you to do just this exact thing. Check out the docs on the email action links, specifically the "Generate password reset email link" section.
// Admin SDK API to generate the password reset link.
const email = 'user#example.com';
admin.auth().generatePasswordResetLink(email, actionCodeSettings)
.then((link) => {
// Do stuff with link here
})
.catch((error) => {
// Some error occurred.
});
Full disclosure - I haven't actually used any of those functions, and I'm a little concerned that the page in question refers a lot to mobile apps - so you might have to pass it the mobile app config.
const actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for
// this URL must be whitelisted in the Firebase Console.
url: 'https://www.example.com/checkout?cartId=1234',
// This must be true for email link sign-in.
handleCodeInApp: true,
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
// FDL custom domain.
dynamicLinkDomain: 'coolapp.page.link'
};
On the other hand, the page also says these features provide the ability to:
Ability to customize how the link is to be opened, through a mobile
app or a browser, and how to pass additional state information, etc.
Which sounds promising, allowing it to open in the browser... but if you are developing for web - and the function errors out when not provided iOS/Android information... then I'm afraid you'll have to do it the old fashioned approach and create your own implementation... but I'm leaning towards this .generatePasswordResetLink should work for you.

How to get user parameters using Amazon Cognito hosted Web UI

Recently I was using the Sign-up and Sign-in template similar this one developed by Vladimir Budilov.
But now, I've been modifying my application to use the hosted UI developed by Amazon. So my application redirects to the hosted UI, all the authentication is made there and they send me the authentication token, more os less as explained in this tutorial.
Summarizing, I call the hosted UI and do login:
https://my_domain/login?response_type=token&client_id=my_client_id&redirect_uri=https://www.example.com
I'm redirected to:
https://www.example.com/#id_token=123456789tokens123456789&expires_in=3600&token_type=Bearer
So, I have now the token_id but I can't get the current user or user parameters from this. Could anyone help me with informations or some directions?
I've tried the methods in Amazon developer guide .
It works well when I was using Vladimir Budilov's template but trying to use the token_id, I'm not succeeding. Thanks in advance for your time and help.
var data = {
UserPoolId : '...', // Your user pool id here
ClientId : '...' // Your client id here
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
if (cognitoUser != null) {
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId : '...' // your identity pool id here
Logins : {
// Change the key below according to the specific region your user pool is in.
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>' : session.getIdToken().getJwtToken()
}
});
// Instantiate aws sdk service objects now that the credentials have been updated.
// example: var s3 = new AWS.S3();
});
}
The attributes you configure to be added as claims are already available inside the id_token with base64 encoding (Since its a JWT token).
You can decode the token and access these attributes both at Client Side using Javascript and on Server.
For more info refer the StackOverflow question How to decode JWT tokens in JavaScript.
Note: If you need to trust these attributes for a backend operation, make sure you verify the JWT signature before trusting the attributes.
Here's a specific example of how to parse the callback parameters and set up a user session. This could be initiated in onLoad of your page.
import { CognitoAuth } from 'amazon-cognito-auth-js';
const authData = {
ClientId : '<TODO: add ClientId>', // Your client id here
AppWebDomain : '<TODO: add App Web Domain>',
TokenScopesArray : ['<TODO: add scope array>'], // e.g.['phone', 'email', 'profile','openid', 'aws.cognito.signin.user.admin'],
RedirectUriSignIn : '<TODO: add redirect url when signed in>',
RedirectUriSignOut : '<TODO: add redirect url when signed out>',
IdentityProvider : '<TODO: add identity provider you want to specify>', // e.g. 'Facebook',
UserPoolId : '<TODO: add UserPoolId>', // Your user pool id here
AdvancedSecurityDataCollectionFlag : '<TODO: boolean value indicating whether you want to enable advanced security data collection>', // e.g. true
Storage: '<TODO the storage object>' // OPTIONAL e.g. new CookieStorage(), to use the specified storage provided
};
const auth = new CognitoAuth(authData);
auth.userhandler = {
onSuccess: function(result) {
alert("Sign in success");
showSignedIn(result);
},
onFailure: function(err) {
alert("Error!");
}
};
const curUrl = window.location.href;
auth.parseCognitoWebResponse(curUrl);
Now you're "signed in" as far as the Cognito JS client is concerned, and you can use getCurrentUser(), getSession(), etc. `See "Use case 2" here for more context/details.

Microsoft Graph API - 403 Forbidden for v1.0/me/events

I'm building a page with numerous calls to Microsoft Graph to different end points: to get OneDrive files, emails, user properties, etc.
The one call that does not work is to get the current user's calendar events. The end point I'm using is https://graph.microsoft.com/v1.0/me/events. The response is 403 Forbidden.
According to the Microsoft documentation here the application needs Calendars.Read or Calendars.ReadWrite permissions. I checked both of these under delegated permissions and still the same problem. I then ticked all 51 permission scopes in Azure AD for this app, and still the same problem.
I also tried creating a new app in Azure AD, but this did not help.
How can I use Microsoft Graph to get back the current user's calendar events? What am I missing?
EDIT:
I'm using ADAL.js for authentication. This is the code I have in my own doAuth function that takes in the client ID of the application.
function doAuth(clientId) {
var variables = {
// Domain of Azure AD tenant
azureAD: // the appropriate URL,
// ClientId of Azure AD application principal
clientId: clientId,
// Name of SharePoint tenant
sharePointTenant: // the appropriate URL
}
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage"
}
var authContext = new AuthenticationContext(config);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
var user = authContext.getCachedUser();
var token = authContext.getCachedToken(clientId);
if (!user || !token)
authContext.login();
return authContext
}
It sounds like you've changed the scopes assigned to the application. When this happens you also need to have user's reauthorize using those new scopes. To do this, add &prompt=consent to the query string of your initial ODATA redirect. This will force your new scopes to be presented to the user for authorization.
You can trigger this in the ADAL.js library using the extraQueryParameter parameter in your configuration:
// Create config and get AuthenticationContext
window.config = {
tenant: variables.azureAD,
clientId: variables.clientId,
postLogoutRedirectUri: window.location.origin,
endpoints: {
graphApiUri: "https://graph.microsoft.com",
sharePointUri: "https://" + variables.sharePointTenant + ".sharepoint.com",
},
cacheLocation: "localStorage",
extraQueryParameter: "prompt=consent"
}
In the end I wasn't able to figure this out and ended up using the Exchange API instead of Graph for mail, calendar and tasks (tasks would have required Exchange API anyway, since this is only currently available in the beta Graph API).

Nativescript {N} oAuth plugin - Retrieve User Facebook Data

Context
I'm attempting to create an Android app with Nativecript using JavaScript. On the first page, it asks the user to connect with Facebook, and I intend to verify whether or not an account exists with their email address.
Tools
I'm using the nativescript-oauth package to handle the OAuth connection to Facebook. I'm working on a Windows 10 machine via command line.
Code
app.js
var tnsOAuthModule = require("nativescript-oauth");
var facebookInitOptions = TnsOAuthOptionsFacebook = {
clientId: 'REDACTED',
clientSecret: 'REDACTED',
scope: ['email']
};
tnsOAuthModule.initFacebook(facebookInitOptions);
application.start({ moduleName: "views/start/start" });
start.js
//...
var tnsOAuthModule = require("nativescript-oauth");
//...
exports.fbConnect = function(){
console.log("Facebook Connect button tapped");
tnsOAuthModule.login()
.then(()=>{
console.log('logged in');
var token = tnsOAuthModule.accessToken();
console.log("FB Auth token: " + token);
console.log(JSON.stringify(tnsOAuthModule));
})
.catch((er)=>{
console.log(er);
});
console.log("Login sucessful");
}
What goes wrong
The above outputs the following:
JS: Facebook Connect button tapped
...
JS: logged in
JS: FB Auth token: EAAC50oamJosBAF1F3lrGAOntENgSAZA40w4iE3rNOLP1W_REDACTED_Cb7yS9ZB1Ro4qhLroOMwZD
JS: {"instance":{"tokenResult":{"accessToken":"EAAC50oamJosBAF1F3lrGAOntENgSAZA40w4iE3rNOLP1W_REDACTED_Cb7yS9ZB1Ro4qhLroOMwZD","accessTokenExpiration":"2017-03-24T18:27:04.176Z","refreshTokenExpiration":"2017-03-24T18:27:04.176Z"},"credentials":{"authority":"https://www.facebook.com/dialog","tokenEndpointBase":"https://graph.facebook.com","authorizeEndpoint":"/oauth","tokenEndpoint":"/v2.3/oauth/access_token","clientId":"REDACTED","clientSecret":"REDACTED","redirectUri":"https://www.facebook.com/connect/login_success.html","scope":"email"}}}
JS: Application started successfully
As you can see, I successfully authorise the Facebook app and retrieve a working access key and can parse the object that is returned - however I'm trying to retrieve the users' email address. I can see that the "email" is within the scope.
Question
How can I use the nativescript-oauth plugin, or the data from the above object, to retrieve the users' email address, as defined the in scope?
Resources
Nativescript homepage - https://www.nativescript.org/
nativescript-oauth GitHub page - https://github.com/alexziskind1/nativescript-oauth
Nativescript official release of OAuth plugin - https://www.nativescript.org/blog/introducing-the-nativescript-oauth-plugin
You must change the scope to get more details(add "user_friends" to get their friend's list, add "public_profile" for profile info)
var facebookInitOptions = TnsOAuthOptionsFacebook = {
clientId: 'REDACTED',
clientSecret: 'REDACTED',
scope: ['email', 'user_friends', 'public_profile']
};
Lastly, in your "App review" section of your facebook developer page, ensure those scope fields are active and shown(they will have a green dot next to them with description of data). You might need to make the app live/start a submission to get approval first if the above code doesn't work.

Categories

Resources