I know a few circumstances where an Refresh Token expires, or becomes invalid:
1. Your software
revoked the token. In other words, your software has a Logout function and that was successfully called.
2. That user went to his Google account settings, Security, and then Manage third party access (
direct link). He saw your OAuth2 client (here called "third party app", clicked on it, and then clicked "Remove Access".
3.
The Refresh token expired because it was not used in six months. By
usage, it means obtaining an access token using that particular Refresh
token.
4. The user granted your OAuth2 client over 50 times
access, without logging out in between. For instance, you have a web
application storing the refresh token in a cookie, and the user destroys
his cookies every now and when. Because of that, he has to log in
because the old tokens were never revoked. Now, if you also use that
same OAuth2 client in an app, then at one point the refresh token for
that app will become invalid.
5. The most likely reason: the
requested OAuth2 scope was not limited to adwords, it also contained one
or more gmail scopes. In that case, when a user changes his password,
all refreshtokens with a gmail scope become invalid.
A
few years ago I noticed that the last reason was incomplete. You get
the same behaviour if a Google Analytics scope is included. I am not sure
if this is still the case, this behaviour has never been officially
documented.
When you do get to the bottom of it, please post your findings!