External OAuth2 with Google doesn't seem to auto refresh token

I implemented external oauth2 authentication with Google as the auth provider, and my own application server as a resource provider. Things are working. However, I noticed that almost every hour as a Forge app user, I am promot with

“This app requires additional access to your account. [Configure access] button”

Also, in the log, there is an entry

  "message": "Authentication required",
  "stack": "",

and as a user, I need to authorize with Google every hour.

As a developer, I thought Forge platform takes care of OAuth2 token refresh. What could I do possibly wrong? How can I debug this?

I did more investigation. I think I can confirm this is a Forge bug.

On one hand, I debugged the access_token sent by Forge to external resource provider, I decoded the token at https://oauth2.googleapis.com/tokeninfo?access_token=XXXX . The token has "access_type": "online", which is wrong, it should be offline instead

On the other hand, I used my Google OAuth2 app’s Client ID and Secret to perform manual testing with curl. I could get the refresh_token as well the offline type access_token. My manual testing steps below:

  1. Go to https://myaccount.google.com/permissions , and revoke the existing app access
  2. Put this URL into the browser to acquire an authorization code
# Authorization link.  Place this in a browser and copy the code that is returned after you accept the scopes.

# Exchange Authorization code for an access token and a refresh token.
curl \
--request POST \
--data "code=[Authentcation code from authorization link]&client_id=[Application Client Id]&client_secret=[Application Client Secret]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code" \

The step 2 link is from documentation Using OAuth 2.0 for Web Server Applications | Authorization | Google Developers

This Forge bug can be triple confirmed by use the Chrome dev tools → Network to monitor the “Configure access“ (Consent flow)

One can see the request URL that Forge sends the user to is like this


response_type = code
client_id     = *******************.apps.googleusercontent.com
redirect_uri  = https://id.atlassian.com/outboundAuth/finish
state         = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb250YWluZXJJZCI6IjUzMWNkODFiLTgxYzItNDA4Ni1hYTdlLTE2MGIxY2MwMmRkOF9hY2EzNmZiNC1mZTU2LTQ2MTEtYjIyMC1lZWFhMGQ0NTI1NzQiLCJzZXJ2aWNlS2V5IjoiYWNybyIsImFhSWQiOiI1ZGY3ZTRkOWJmN2RjMDBjYjljMmI1YjAiLCJyZWRpcmVjdFVybCI6Imh0dHBzOi8vcG9wdXAvIiwic2NvcGVzIjpbImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvdXNlcmluZm8uZW1haWwiLCJwcm9maWxlIl0sImNvbnRleHRBcmkiOiJhcmk6Y2xvdWQ6amlyYTo6c2l0ZS83ZjhmZTUwMC1iNTA5LTQyMDMtOTQyYi1hZGI1YmQzNWZlYWMiLCJ2ZXJzaW9uIjoiOTRhODMyMjItMWIzMy00MWMxLTg4MjQtYTU3MTAzYjg0YjAyOjEyLjExOC4wIiwiaWF0IjoxNjY2ODgyNjE2LCJleHAiOjE2NjY4ODYyMTYsImlzcyI6IjkxZTNkY2VkLWI4NjgtNDBhZS1hMGE3LWMwYjM4N2Y4MjFhMiJ9.mc7-FLEsaX9cngzQ8HabSUBbVI08VUcknASZYlW1US0
scope         = https://www.googleapis.com/auth/userinfo.email profile

Please note the missing access_type=offline parameter. As Google OAuth2 documentation specify this parameter is required for getting a refresh_token

I reported this issue as a bug to Atlassian. They updated the doc https://developer.atlassian.com/platform/forge/use-an-external-oauth-2.0-api-with-fetch/#refresh-tokens to include a previously undocumented feature to support refresh token.