Avoid unnecessary token refresh
See original GitHub issueFeature Description
Access tokens that are generated for communicating for Google APIs are short-lived tokens which are only valid for one hour. Once expired, a new access token can be requested using the refresh token received during a user’s initial connection. The refresh token is much longer lived and requires going through oAuth again to get a new one. The underlying PHP API Client library for Google APIs handles refreshing access tokens automatically on-the-fly when needed when a request is made.
As we have started to move away from batch requesting all data via Site Kit’s /data
REST endpoint and more towards a more traditional API architecture (making one request per endpoint), this has introduced the potential for multiple access tokens to be requested at the same time.
The most common situation for this would be on the WordPress dashboard, right after logging in for the first time in over an hour. If Analytics is connected, this would result in 4 separate requests to the Google API at the same time and since the access token would be expired at the time the request is made, a new token would be requested in each case, used once and only the last one would be kept.
4 consecutive requests to /o/oauth2/token/
followed by 4 requests to Google APIs (3 for Analytics, 1 for Search Console)
While the on-demand token refreshing is important, we should see how to avoid such cases where more tokens are requested than needed.
Do not alter or remove anything below. The following sections will be managed by moderators only.
Acceptance criteria
- Instead of mainly relying on the automated on-demand refresh of access tokens that are about to expire (which is built into the Google PHP client library), Site Kit should proactively refresh the current user’s access token in that case, outside of REST API requests which may come in multiple at a time, causing the problem outlined. (Note that this is not a major problem, so we do not need to prevent it - but we should avoid it where possible.)
- On pageload: If the current user has an access token which will expire in the next 30 seconds or less, that access token should be refreshed, relying on the existing
OAuth_Client::refresh_token()
method (which used to be used, but has for a while now been unused). - The same logic should run for every WordPress “heartbeat” request (see
heartbeat_tick
action), so that it also works in the case that the user stays on a Site Kit screen without a page reload for longer than the access token expiry.
- On pageload: If the current user has an access token which will expire in the next 30 seconds or less, that access token should be refreshed, relying on the existing
Implementation Brief
- Add new hooks for
admin_init
andheartbeat_tick
actions to theAuthentication
class:- Get the current token using
$this->token->get()
method; - Return early if the current token is empty or it doesn’t exire in less than 30 seconds;
- Call
$this->get_oauth_client()->refresh_token()
method.
- Get the current token using
Test Coverage
- N/A
Visual Regression Changes
- N/A
QA Brief
- Stop your local environment
- Configure HTTP proxy on your local machine following instructions in the engineering workflow doc.
- Reset token creation time by running the following command:
10updocker wp user meta set 1 wp_googlesitekit_access_token_created_at 1
- Start the mitmproxy app
- Start your local environment
- Open a non-sitekit admin page (for example
Appearance > Themes
: /wp-admin/themes.php). - Check the mitmproxy log and confirm that you see only one request to the
https://sitekit.withgoogle.com/o/oauth2/token/
endpoint.
Changelog entry
- Avoid potentially simultaneous token refresh requests by proactively refreshing soon-to-expire tokens.
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (2 by maintainers)
QA: ✅
wp user meta set 1 wp_googlesitekit_access_token_created_at 1
/wp-admin/themes.php
@felixarntz found one more issue in the
OAuth_Client::refresh_token
method that prevented token refresh on non-sitekit pages. Therefresh_token
method tried to access not initializedgoogle_client
instance instead of using theget_client()
method, which caused early return and left token not refreshed.Do you mind reviewing #4062?