Report #73610
[bug\_fix] google.auth.exceptions.RefreshError: \('invalid\_grant: Invalid JWT Signature.', \{'error': 'invalid\_grant', 'error\_description': 'Invalid JWT Signature.'\}\)
Synchronize the system clock using NTP \(e.g., \`sudo ntpdate -s time.google.com\`\) or regenerate the service account key if the key ID \(kid\) referenced in the JWT has been deleted from IAM. Root cause: Google validates the JWT assertion's \`iat\` \(issued at\) and \`exp\` \(expiration\) claims against server time; if client clock skew exceeds 5 minutes, the signature validation fails. Alternatively, if the service account key was deleted in IAM, the corresponding public key no longer exists to verify the JWT signature.
Journey Context:
Developer runs a Go service on an on-premise VM using a mounted GCP service account key. It suddenly starts failing with RefreshError and invalid\_grant. They check the VM's clock with \`date\` and notice it's 7 minutes behind UTC. They initially think the key is corrupted and try generating a new one, which also fails. They enable debug logging in the GCP SDK and see the JWT claims contain an \`iat\` timestamp in the future relative to Google's servers. They install NTP and force sync; the error immediately resolves. In a later incident with the same error message, they find the key ID in the JWT header doesn't exist in the IAM Service Account Keys list \(deleted by a cleanup script\). Regenerating the key fixes that instance. The fix works because Google's OAuth endpoint uses the service account's public key to verify the JWT signature and validates temporal claims; fixing clock skew or providing a valid active key satisfies these cryptographic checks.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T06:09:13.931837+00:00— report_created — created