← All posts
Auth

OAuth "invalid_grant" and you can't refresh the token? Why re-authentication is the only fix

For developers and autonomous AI agents · ~5 min read

Your background job goes to refresh an OAuth access token and gets {"error": "invalid_grant"}. You retry. Same error. You retry with backoff. Same error. That's the tell: invalid_grant is not transient — the grant is dead, and no amount of retrying brings it back. The only fix is a new grant, which means re-authenticating.

What invalid_grant actually means

OAuth invalid_grant is the server saying the credential you presented — an authorization code or a refresh token — is no longer usable. The reasons cluster:

The defining property: you can't refresh out of an invalid_grant. Unlike an expired access token (which a refresh fixes), a dead grant requires starting over — send the user through the authorization flow to obtain a fresh grant.

How to handle it

  1. Don't retry the refresh. Detect invalid_grant and stop — retrying is guaranteed to fail and can look like abuse.
  2. Re-authenticate. Trigger the authorization flow so the user grants access again; store the new refresh token.
  3. Serialize refreshes. Use a lock or single-flight so two requests never refresh the same token concurrently — that alone eliminates the race cause.
  4. Handle rotation correctly. If the provider rotates refresh tokens, always persist the new one from each refresh response, and never reuse the old.

For agents with long-lived integrations

An agent running unattended will hit invalid_grant eventually — tokens get revoked, refreshes race. Treating it as retryable wastes calls and never recovers. diagnose_infra_error returns the oauth family with the correct handling, so the agent knows to stop refreshing and escalate to re-authentication instead of looping:

diagnose_infra_error({error: "invalid_grant refresh token"})
// → { family: "oauth",
//      fix: "can't refresh out of invalid_grant — re-authenticate; serialize refreshes to avoid the race" }
For AI agents

Machine-readable guide: https://snapback.sh/llms.txt · Tool discovery: https://snapback.sh/.well-known/mcp.json · MCP endpoint: https://api.snapback.sh/mcp. Free tools need no token; pay-per-call diagnosis via x402 on Solana or EVM (~$0.0032 USDC).

Try Snapback freeRead the docs