1

I am working on an e-commerce project built with React & nodejs (on MongoDB). I have recently refactored my users route(NodeJS) to integrate account verification system(new user registration/account creation phase) using googleapis and nodemailer.

The account verification system integration went successful for the past 7 days. But since recently my server start to trow the following error in the back-end every time a new request is sent to the user/register end point.(Every time a user tried to register/create an account).

Emailsent... GaxiosError: invalid_grant
    at Gaxios._request (/home/hyf/Documents/Ultimate-Path/e-commerce/server/node_modules/gaxios/build/src/gaxios.js:129:23)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
    at async OAuth2Client.refreshTokenNoCache (/home/hyf/Documents/Ultimate-Path/e-commerce/server/node_modules/google-auth-library/build/src/auth/oauth2client.js:174:21)
    at async OAuth2Client.refreshAccessTokenAsync (/home/hyf/Documents/Ultimate-Path/e-commerce/server/node_modules/google-auth-library/build/src/auth/oauth2client.js:198:19)
    at async OAuth2Client.getAccessTokenAsync (/home/hyf/Documents/Ultimate-Path/e-commerce/server/node_modules/google-auth-library/build/src/auth/oauth2client.js:227:23)
    at async sendMail (/home/hyf/Documents/Ultimate-Path/e-commerce/server/dallolEmail.js:21:26) {
  response: {
    config: {
      method: 'POST',
      url: 'https://oauth2.googleapis.com/token',
      data: 'refresh_token=1%2F%2F04djMTiSxQlnDCgYIARAAGAQSNwF-L9IrHQIKWgPp1rwNmOzTYGqdUc3ze4SvAGneBjqn6rZL4qtZvWpbnA4DlU4yMBB0Ie1epAQ&client_id=566826891486-r4n7nkafn2bsr0dbt6rd1bk38ar5mgja.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token',
      headers: [Object],
      paramsSerializer: [Function: paramsSerializer],
      body: 'refresh_token=1%2F%2F04djMTiSxQlnDCgYIARAAGAQSNwF-L9IrHQIKWgPp1rwNmOzTYGqdUc3ze4SvAGneBjqn6rZL4qtZvWpbnA4DlU4yMBB0Ie1epAQ&client_id=566826891486-r4n7nkafn2bsr0dbt6rd1bk38ar5mgja.apps.googleusercontent.com&client_secret=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&grant_type=refresh_token',
      validateStatus: [Function: validateStatus],
      responseType: 'json'
    },
    data: {
      error: 'invalid_grant',
      error_description: 'Token has been expired or revoked.'
    },

I tried to look around for similar bugs here; However most of them are focusing on "gmail authentication for login" instead of sending email for account verification. I have also tried to read the googleapis documentation. But still I got only a solution on how to regenerate a new USER_API_SECRET_KEY, no explanation about regenerating a new refresh-token.

I would really appreciate if you can give me some explanation on how I can regenerate the google API refresh token every-time it expires.

require("dotenv").config();
const nodemailer = require("nodemailer");
const {google} = require("googleapis");

const CLIENT_ID = process.env.GMAILER_CLIENT_ID;
const CLIENT_SEC = process.env.GMAILER_CLIENT_SEC;
const REDIRECT_URI = process.env.GMAILER_REDIRECT_URI;
const Gmail_Ref_Token = process.env.GMAILER_REFRESH_TOKEN;

const oAuth2Client = new google.auth.OAuth2(
  CLIENT_ID,
  CLIENT_SEC,
  REDIRECT_URI
);
oAuth2Client.setCredentials({refresh_token: Gmail_Ref_Token});

 const sendMail = async (mailOptions) => {
  try {
    const gaccessToken = await oAuth2Client.getAccessToken();
    //Transporter
    const transport = nodemailer.createTransport({
      service: "gmail",
      auth: {
        type: "OAuth2",
        user: "mt@gmail.com",
        clientId: CLIENT_ID,
        clientSecret: CLIENT_SEC,
        refreshToken: Gmail_Ref_Token,
        accessToken: gaccessToken,
      },
    });
//Mail Options
    const mailOptions = {
    from: "noreplay@dm.com || <mt@gmail.com>",
    to: `${email}`,//!email collected from the req.body.email
    subject: "Email Activation",
    text: `Please Activate your DM account,copy and paste the following link into your browser ${process.env.CLIENT_URL}/register/activation/${emailActivationToken} `,
    html: `<h3>Please Activate your DM account</h3>

  <p><Strong>Click the given link to redirect to the <a href=${process.env.CLIENT_URL}/register/activation/${emailActivationToken}>account activation page.</a> </strong></p>
  

    <strong>Best Regards</strong>
    <p>Michael T<p>
    <strong>DM</strong>
    `,
    };

    const result = await transport.sendMail(mailOptions);
    return result;
  } catch (error) {
    return error;
  }
};

sendMail()
  .then((result) => console.log("Email sent...", result))
  .catch((err) => console.log(error.message));

  module.exports = sendMail
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Michael
  • 21
  • 1
  • 6

1 Answers1

0

When you use a refresh token to get a new access token (depending on the backend setup) you might also get back a new refresh token. Many systems starts to use one-time refresh tokens, that only can be used one time and each time you use it, you get back a new one.

They do this to improve the security, in case a refresh token is stolen.

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40