skip to Main Content

I upgraded a 4 years old cloud function from gen 1 to gen 2 using defineSecret instead of functions.config() to get environment variables and using OAuth2 authentication instead of having my gmail setup to authorize "less secure apps".

The function deploys successfully but when I run it I get an "invalid user or password" error. The function is a simple one that takes the data from a contact form and emails it to me, using my gmail as sender.
I have OAuth consent screen on testing mode with my email as a test user.
I generated a refresh token with OAuth 2.0 Playground using this API: https://www.googleapis.com/auth/gmail.send

Here is the exact log:

Access Token obtained successfully

Error creating transport: Error: Invalid login: 535-5.7.8 Username and Password not accepted.

EDIT

Here is the function:

const clientId = defineSecret("CLIENT_ID");
const clientSecret = defineSecret("CLIENT_SECRET");
const refreshToken = defineSecret("REFRESH_TOKEN");

async function getAccessToken(oauth2Client) {
  try {
    const { token } = await oauth2Client.getAccessToken();
    return token;
  } catch (error) {
    console.error('Error getting access token:', error);
    throw new Error(`Failed to get access token: ${error.message}`);
  }
}

const createTransport = async () => {
  try {
    const oauth2Client = new google.auth.OAuth2(
      await clientId.value(),
      await clientSecret.value(),
      "https://developers.google.com/oauthplayground"
    );

    oauth2Client.setCredentials({
      refresh_token: await refreshToken.value()
    });

    const accessToken = await getAccessToken(oauth2Client);
if (!accessToken) {
      throw new Error('Failed to obtain access token');
    }

    console.log('Access Token obtained successfully');
    
    const transportConfig = {
      host: 'smtp.gmail.com',
      port: 465,
      secure: true,
      auth: {
        type: 'OAuth2',
        user: await emailSender.value(),
        clientId: await clientId.value(),
        clientSecret: await clientSecret.value(),
        refreshToken: await refreshToken.value(),
        accessToken,
      },
    };

const transporter = nodemailer.createTransport(transportConfig);
    
    await transporter.verify();
    console.log('SMTP connection verified successfully');
    
    return transporter;
  } catch (error) {
    console.error('Error creating transport:', error);
    throw new Error(`Failed to create transport: ${error.message}`);
  }
};

2

Answers


  1. Chosen as BEST ANSWER

    The problem was related to the API that I was using. Since my function does nothing else than sending an email with my gmail account, I thought that using https://www.googleapis.com/auth/gmail.send in the OAuth 2.0 playground would be enough but no. I had to authorize full access to my gmail account with https://mail.google.com/ and now the function is working.


  2. Have you binded the secret to the function?
    If you have, you can share the part of the code where you initialized the secret?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search