Colin: Did you make any headway with this? One of the problems with OAuth is that when problems arise it's hard to see what's happening under the hood. You could try adding some debugging to lib/classes/oauth2/client.php to display the response when there's an error (i.e. insert the six lines after line 255):
233 public function upgrade_refresh_token(system_account $systemaccount) {
⋮
255 if ($this->info['http_code'] !== 200) {
256 error_reporting(E_ALL);
257 error_log("[OAuth Debug] HTTP status: " . $this->info['http_code']);
258 if ($this->error) {
259 error_log("[OAuth Debug] Curl error" . $this->error);
260 }
261 error_log("[OAuth Debug] Response: $response");
262 throw new moodle_exception('Could not upgrade oauth token');
263 }
This should send some debug output to the shell if the scheduled task is run at the CLI, or to the PHP error_log if run via the web interface. E.g. if I break my issuer and run the scheduled task I see:
# sudo -u apache php admin/tool/task/cli/schedule_task.php --execute=\\core\\oauth2\\refresh_system_tokens_task
Execute scheduled task: Refresh OAuth tokens for service accounts (core\oauth2\refresh_system_tokens_task)
[OAuth Debug] HTTP status: 400
[OAuth Debug] Response: {"error":"unsupported_grant_type","error_description":"Grant type \"refresh_token\" not supported"}
which shows what the issuer didn't like about the request. Fingers crossed the output for Google will be similarly helpful.