Melvin Kucuk
Melvin Kucuk

Reputation: 67

Error invalid grant OAuth2 with Nodemailer and Firebase Cloud Functions

I have the next problem. I implemented in firebase cloud functions with NodeJs, Typescript, OAuth2, Gmail. I followed one tutorial similar like this one https://dev.to/chandrapantachhetri/sending-emails-securely-using-node-js-nodemailer-smtp-gmail-and-oauth2-g3a

I will attach the code below. The problem is that in some way the Refresh Token is revoked or expired, it last around 8 days. My workarround is generate a new Refresh Token in https://developers.google.com/oauthplayground like explained in the tutorial and that fixes requesting for new Access Token for 8 days aprox. I tried a lot of thigs but did not succeed.

The error provided in the cloud functions logs is something similar to this with a lot of other things that one cannot comprehend

{
   error: 'invalid_grant',
   error_description: 'Token has been expired or revoked.' 
}

Can someone help me with this?

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as nodemailer from "nodemailer";
import * as goole from "googleapis";
admin.initializeApp();

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript

export const mailPedidos = functions.firestore
  .document("example/{exampleId}")
  .onCreate(async (snapshot, context) => {

    //business logic removed
    let name = "Carl";        
    let mail = "[email protected]";
    const mailOptions = {
      from: "Kuxon <[email protected]>",
      to: mail,
      subject: "Example Subject",
      html: `<p style="font-size: 16px;">Name: ${name} </p>
            `, // email content in HTML
    };

    try {
      const CLIENT_ID =
        "CLIENTID";
      const CLIENT_SECRET = "CLIENTSECRET";
      const REDIRECT_URI = "https://developers.google.com/oauthplayground";
      const REFRESH_TOKEN =
        "REFRESHTOKEN";

      const oAuth2Client = new goole.google.auth.OAuth2(
        CLIENT_ID,
        CLIENT_SECRET,
        REDIRECT_URI
      );
      oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });

      const accessToken = await oAuth2Client.getAccessToken();
      console.log("Access Token: " + accessToken);

      let aT: string | undefined = "";

      if (accessToken.token !== null) {
        aT = accessToken.token;
      }

      console.log("Access Token token: " + aT);

      const transporter = nodemailer.createTransport({
        service: "gmail",
        auth: {
          type: "OAuth2",
          user: "[email protected]",
          clientId: CLIENT_ID,
          clientSecret: CLIENT_SECRET,
          refreshToken: REFRESH_TOKEN,
          accessToken: aT,
        },
      });

      // returning result
      transporter.sendMail(mailOptions, (error: any, info: any) => {
        if (error) {
          console.log(error.toString());
        }
        console.log("Sended");
      });
    } catch (error) {
      console.log({ error });
    }
    return snapshot;
  }); 

Upvotes: 1

Views: 1202

Answers (1)

Michael
Michael

Reputation: 46

This could be because of the configuration of the google cloud platform.

A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.

link to the relevant thread: Do google refresh tokens expire?

Upvotes: 1

Related Questions