It appears that the expiry does not apply to the individual refresh token, but the chain of tokens generated after the user initiates the OAuth2 flow. I see a repeatable pattern of the rotations working for exactly 30 days, followed by a 403.
Still waiting on a response from Atlassian… We may have to fall-back on OAuth1, since it is pretty unreasonable to ask app users to periodically re-auth.
I haven’t found a solution yet, but I am digging into @tbinna’s idea. He suggested, that the problem actually starts one token refresh request earlier when the response from auth.atlassian.com is missing the refresh_token property.
The latest official info I was able to find was in this massive thread:
If I understand @Nir’s statement, this is actually a bug that makes all the refresh tokens invalid after 30 days regardless of whether they are used/rotated or not.
Sadly, the above does not explain the missing refresh_token property in some of the responses.