Google OAuth2.0 - Gaxios invalid_grant error - node.js

The below is my mailer.js code
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const { OAuth2 } = google.auth;
const oauth_link = "https://developers.google.com/oauthplayground";
const { EMAIL, MAILING_ID, MAILING_REFRESH, MAILING_SECRET } = process.env;
const auth = new OAuth2(
MAILING_ID,
MAILING_SECRET,
MAILING_REFRESH,
oauth_link
);
exports.sendVerificationEmail = (email, name, url) => {
console.log("inside send verification email");
auth.setCredentials({
refresh_token: MAILING_REFRESH,
});
const accessToken = auth.getAccessToken();
console.log("accessToken-" + accessToken);
const smtp = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: EMAIL,
clientId: MAILING_ID,
clientSecret: MAILING_SECRET,
refreshToken: MAILING_REFRESH,
accessToken,
},
});
console.log("smtp " + smtp);
const mailOptions = {
from: EMAIL,
to: email,
subject: "Facebook email verification",
html: '<div><div style="max-width:500px;margin-bottom:1rem;align-items:center;display:flex"><img style="width:40px" src="https://seeklogo.com/images/F/facebook-icon-circle-logo-09F32F61FF-seeklogo.com.png" alt=""><span style="font-family:sans-serif;color:#3266a8;font-weight:700;padding-left:10px">Action Required : Activate your facebook account</span></div><div style="border-top:1px solid;border-bottom:1px solid;border-color:#deb887;padding:10px;padding-bottom:20px"><div style="height:35px"><span style="font-weight:700;font-family:sans-serif">Hello ${name}</span></div><div style="height:28px;font-family:sans-serif;padding-bottom:20px"><span>You recently created a profile on facebook. Please confirm your account</span></div><div style="">Confirm Your Account</div></div></div>',
};
console.log("mailOptions" + mailOptions);
smtp.sendMail(mailOptions, (err, res) => {
if (err) return err;
return res;
});
};
I have properly generated the Oauth playground configurations and have the below in my process.env
EMAIL=***
MAILING_ID=***
MAILING_SECRET=***
MAILING_REFRESH=***
MAILING_ACCESS=***
I am getting the below error.
GaxiosError: invalid_grant
***
***
data: {
error: 'invalid_grant',
error_description: 'Token has been expired or revoked.'
},
I am totally beginner with the Google OAuth procedure. Which token has expired? Is it Access token or Refresh Token.
Thanks in advance, Dear Developers community..

The refresh token you are using has expired. You need to request a new one. If your project is still in testing refresh tokens only last for seven days.
You need to set it to production in Google cloud console under the OAuth screen and your refresh tokens will no longer expire
I applaud your use of xOAuth2 with the smtp server 👏

Related

How to Resolve Error Sending Email Using nodemailer googleapi?

Last week I initially posted this asking for help using nodemailer and googleapi. I'm trying to use nodemailer and googleapis to send an email. I have set up my project in https://console.cloud.google.com/ and have set my CLIENT_ID, CLIENT_SECRET, CLIENT_REDIRECT_URI and REFRESH_TOKEN in a .env and have confirmed that the values are being populated. In debug mode I have noticed the following error stack when I send the error:
'Error: invalid_grant\n at Gaxios._request (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/gaxios/build/src/gaxios.js:130:23)\n at processTicksAndRejections
(node:internal/process/task_queues:96:5)\n
at async OAuth2Client.refreshTokenNoCache (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:174:21)\n
at async OAuth2Client.refreshAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:198:19)\n
at async OAuth2Client.getAccessTokenAsync (/Users/ENV/Tutoring-Invoice-Management-System/node_modules/google-auth-library/build/src/auth/oauth2client.js:227:23)\n
at async sendMail (/Users/ENV/Tutoring-Invoice-Management-System/service/send-email.js:17:29)'
The code is below. I have edited it based on an answer to the question already. My question now is, why am I getting the invalid_grant error? Based on the formal documentation I have set everything up correctly in https://console.cloud.google.com/apis/credentials/oauthclient. But perhaps there is an issue there?
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
require('dotenv').config();
console.log("CLIENT_ID: " + process.env.CLIENT_ID);
console.log("CLIENT_SECRET: " + process.env.CLIENT_SECRET);
console.log("CLIENT_REDIRECT_URI: " + process.env.REDIRECT_URI);
console.log("REFRESH_TOKEN: " + process.env.REFRESH_TOKEN);
const oAuth2Client = new google.auth.OAuth2(process.env.CLIENT_ID, process.env.CLIENT_SECRET, process.env.REDIRECT_URI);
console.log("oAuth2Client: " + oAuth2Client);
oAuth2Client.setCredentials({refresh_token: process.env.REFRESH_TOKEN})
async function sendMail() {
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: 'envolonakis#gmail.com',
to: 'envolonakis#gmail.com',
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
console.log(error.stack);
return error;
}
}
sendMail()
From the official documentation, this is what you need to use:
try {
const accessToken = await oAuth2Client.getAccessToken()
const transport = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 465,
secure: true,
auth: {
type: 'OAuth2'
}
});
const mailOptions = {
from: process.env.OWNER_EMAIL,
to: process.env.RECIPIENT,
subject: "Test Email API Subject",
text: "Test Email API Text",
html: "<h1> Test Email API HTML </h1>",
auth: {
user: process.env.OWNER_EMAIL,
accessToken: accessToken.token
}
}
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
return error;
}
One error that you have whilst using the google api authentication library is with the token. You were passing the complete token object to the auth configuration of nodemailer instead of just the access token string. Another thing to keep in mind, adding or removing parameters to the auth configuration of nodemailer will lead to different errors.
Using #Morfinismo 's solution in addition to creating a new oAuth on https://developers.google.com/oauthplayground resolved my issue.

Error: connect ECONNREFUSED 127.0.0.1:587 – nodemailer & gmail

Dear stack overflow community,
I am dealing with a project and I tried many things, but I can't handle it.
I created a website with NextJS. This Website has a contact form. To send the data from the contact form to the addressee, there is an API which takes the request and with nodemailer I am trying to create a transporter to send the email with Gmail.
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
export default async function (req, res) {
const body = JSON.parse(req.body);
const CLIENT_EMAIL = process.env.CLIENT_EMAIL;
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const REDIRECT_URI = process.env.REDIRECT_URI;
const REFRESH_TOKEN = process.env.REFRESH_TOKEN;
const OAuth2Client = new google.auth.OAuth2(
CLIENT_ID,
CLIENT_SECRET,
REDIRECT_URI
);
OAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });
try {
// Generate the accessToken on the fly
const accessToken = await OAuth2Client.getAccessToken();
// Account authentication config
const authConfig = {
type: "OAuth2",
user: CLIENT_EMAIL,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
refreshToken: REFRESH_TOKEN,
accessToken: accessToken,
};
// Create the email envelope (transport)
const transport = nodemailer.createTransport(authConfig);
// Create the email options and body
// ('email': user's email and 'name': is the e-book the user wants to receive)
const mailOptions = {
from: `${CLIENT_EMAIL}`,
to: body.email,
subject: `${body.name} – ${body.reason}`,
text: `${body.message}`,
};
const result = await transport.sendMail(mailOptions);
return result;
} catch (error) {
console.log(error);
}
res.status(200).json({
message: "Email has been sent",
});
}
The problem is, when the User sends the email, I get the following error message:
Error: connect ECONNREFUSED 127.0.0.1:587
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1161:16) {
errno: -61,
code: 'ESOCKET',
syscall: 'connect',
address: '127.0.0.1',
port: 587,
command: 'CONN'
}
I tried a couple of things now, but I really do not make any progress at this point. I would be super happy if somebody could help me.
Thanks a lot in advance.
Just make http://localhost:8000 to http://127.0.0.1:8000. It works. Windows are not configured to figure this out. An IP address should be in the conventions of numbers.
http://127.0.0.1:8000
The above address is the default one for any computer

Sending an Gmail by OAuth 2.0 Playground

I have written code for sending mail from my gmail account to another account by OAuth2. In OAuth2, we need a refreshToken and accessToken generated on https://developers.google.com/oauthplayground/ The accessToken generated by this will expires in 3600 seconds. I want some code that will generate accessToken.
I have written code where i direct put refreshToken and acessToken from this site https://developers.google.com/oauthplayground/ .
//javascript code main file app.js
async function sendEmail() {
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const OAuth2 = google.auth.OAuth2;
const smtpTransport = nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: "***************#gmail.com",
clientId: "***********.apps.googleusercontent.com",
clientSecret: "*************",
refreshToken: "**************",
accessToken: "********************************"
}
});
const mailOptions = {
from: "**************#gmail.com",
to: "**************#gmail.com",
subject: "Hello",
generateTextFromHTML: true,
html: "<h1>TEST MAIL SAYS HELLO</h1>"
};
smtpTransport.sendMail(mailOptions, (error, response) => {
error ? console.log(error) : console.log(response);
smtpTransport.close();
});
}
sendEmail();
This is working fine but i want that accessToken generated by using some code.
In order to get the access token and refresh token you will need to enter your credentials at some point in your app. This will require some sort of front end portion. On the back end you will use the auth package in the googleapis node library to take those credentials and generate the tokens you need.
Another way is to make a service account that will send emails on behalf of your account. What is the flow you want, anyone to send an email using Gmail or just yourself?

Get an access token to Linkedin API using email and password

Is it possible to get an access token in order to use node-linkedin package by providing credentials - user email and password? What I'm trying to do is an command line app, that can make an api calls to linkedin and write results in a text file. Thus, I'm not sending any api call results to the client.
I've been trying to do the same thing.
the simple-oauth2 module has a method for logging in via password, but I cannot seem to get it to work.
https://www.npmjs.com/package/simple-oauth2
// Set the configuration settings
const credentials = {
client: {
id: '<client-id>',
secret: '<client-secret>'
},
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
};
// Initialize the OAuth2 Library
const oauth2 = require('simple-oauth2').create(credentials);
// Get the access token object.
const tokenConfig = {
username: 'username',
password: 'password'
};
// Callbacks
// Save the access token
oauth2.ownerPassword.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const token = oauth2.accessToken.create(result);
});
I am not sure these endpoints are correct:
auth: {
tokenHost: 'https://api.linkedin.com',
authorizePath: 'https://api.linkedin.com/uas/oauth/requestToken',
tokenPath: 'https://api.linkedin.com/uas/oauth/accessToken'
}
I get a 400 bad request.

Nodemailer XOauth2 [Error: unauthorized_client] when trying to get new access token

I am sending emails through Gmail succefully using nodemailer with xoauth2, but when the time comes to get new access token i receive [Error: unauthorized_client].
My code:
var express = require('express');
var nodemailer = require("nodemailer");
var xoauth2 = require('xoauth2');
app = express();
var generator = xoauth2.createXOAuth2Generator({
user: {userEmail},
clientId: {clientId},
clientSecret: {clientSecret}
refreshToken: {refreshToken},
accessToken: {accessToken}
});
var smtpTransport = nodemailer.createTransport({
service: "gmail",
auth: {
xoauth2: generator
}
});
var mailOptions = {mailOptions}
app.get('/send',
function (req, res) {
generator.generateToken(function (err, token, access) {
console.log(err, token, access);
smtpTransport.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
res.sendStatus(404);
} else {
console.log(response);
res.sendStatus(200);
}
smtpTransport.close();
});
});
});
app.listen(5000);
I am invoking generateToken just for testing purposes. But in normal use is not responding also.
I obtained here Google Developers clientId and clientSecret, where i also added https://developers.google.com/oauthplayground/ to Authorized redirect URIs. After that I went developers playground (the same as the redirect uri), I selected Gmail API with scope mail.google.com, then I exchanged the "Authorization code" for refresh and access tokens and I checked "Auto-refresh the token before it expires". After the timeout has finished (the 3600 seconds) I am not able to obtain new accessToken using xoauth2.
Can be marked as closed. I have not found the reason for that problem. I just deleted the project in Google Developers Console and create new one. In new project i followed the same steps desribed above I and succesfully obtained an access token.
Perhaps you were using
https://developers.google.com/oauthplayground/
instead of
https://developers.google.com/oauthplayground

Resources