According to Googleā€™s docs on OAuth, the server application gets refresh_token from Google (on exchanging the auth code) only if the original redirection request to Google contains the param access_type with value offline (documentation link).

But this is only for the first time a user authenticates with your app. If for some reason your flow takes the user through the authentication flow again without having changed anything (userā€™s Google account, permissions required, etc. Havenā€™t tested with changed permissions yet but definitely happens when permissions also remain the same) then when you exchange auth code for tokens from Google, the Google servers donā€™t return the refresh_token this second time.

This is based on anecdotal observation, and I couldnā€™t find any such mention in their documentation. An answer on Stack Overflow confirmed for me that it wasnā€™t something misconfigured on my end šŸ˜….

A ā€œsolutionā€ for this could be to always specify the param prompt with a value of consent in the original redirect request where we send user to Googleā€™s flow.