Search code examples
oauth-2.0firebase-authenticationgoogle-oauthnodemailerrefresh-token

Using nodemailer & Google OAuth to send email, working for 7 days, but get invalid grant


I've been working to setup Oauth communication for an auto-emailing node.js web app using nodemailer. (I don't wish to use gmail's Less Secure Apps setting).

I've taken steps to get the client id, secret, and refresh token from the oauth playground, and have set up the web app to use a stored refresh token to request new access tokens when it first loads.

It is able to send emails (for about 7 days), then I get error invalid status code 400 on client side, and/or invalid grant on server side.

Going back to google playground and getting another refresh token, then updating it in environment variables, solves this for another week. But I'd like to solve this indefinitely.

I read somewhere "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"... so last week I switched the app to "In Production" (at console.cloud.google.com) and tried having it verified with google. This week, the same issue has recurred suggesting that wasn't the right fix, or that it wasn't yet verified with google.

I don't know if this was done correctly, nor do I know if this is the true solution to this expiring/revoked refresh token, or invalid grant.

I've also come across these explanations:

The user has revoked your app's access.

The refresh token has not been used for six months.

The user changed passwords and the refresh token contains Gmail scopes.

The user account has exceeded a maximum number of granted (live) refresh tokens.

The client has reached a limit of 50 refresh tokens per account if it's not a service account.

(I didn't make ANY changes during the week, so...not sure why these would have changed)

Is the issue the refresh token? Or the status of the application? Would it be dns/cname/cloudflare server issues?


Solution

  • For those who have the same issue in the future: It turned out that google verification wasn't necessary. It seems like the refresh token expiring after a week or 7 days was due to the placement of the oauth2Client.setCredentials() function call and accessToken variable.

    Calling setCredentials() and obtaining the access token INSIDE the SendEmail() function (at runtime, just before sending email, rather than at application start/spinup time) seemed like it enabled the code to more dynamically generate the tokens it needed. After 12 days, it still seems like its working so I'd call this a success.

    My guess at why it wasn't working before was because setting credentials outside of a function meant that code only ran once on server/application startup. It would then store the obtained access token in a const.

    The access token would eventually expire, and even if called again/later inside of a function to obtain a new access token, it would be unable to change the value of a const property/variable, and so the call would inevitably fail after a week when it failed to renew.

    Hope this helps anyone else having a similar issue.
    My apologies for the run-on sentences.