Airtable OAuth refresh token invalid_grant — What it means & how to fix it
How to diagnose and fix Airtable refresh token invalid_grant errors
If you integrate with Airtable using OAuth 2.0, you will eventually see a failed refresh. It often shows up as invalid_grant, and it can break sync jobs, backfills, or user-triggered updates.
This article shows how to diagnose and resolve Airtable refresh token errors, and shares the engineering practices that work best in production (including how to avoid refresh token race conditions and rotation pitfalls). For broader context, see API Auth Is Deeper Than It Looks and Why OAuth Is Still Hard.
Spot the error
When your backend POSTs to Airtable’s token endpoint to swap a refresh token for a new access token:
- Token endpoint:
https://airtable.com/oauth2/v1/token - Common HTTP status:
400 - Common OAuth error:
invalid_grant
Example response payload:
Sometimes Airtable also includes an error_description field with a human-readable reason. Either way, the meaning is consistent: the refresh token you have stored can’t be used to mint a new access token. Retrying the same request will keep failing until you address the underlying cause.
Why did Airtable reject the refresh token?
There are a few recurring root causes. The key is to treat invalid_grant as a token lifecycle problem, not as a transient network problem.
Most common: You’re not using the latest refresh token
Some OAuth providers rotate refresh tokens. Airtable does: when a refresh token is exchanged, the previous access and refresh tokens are invalidated and new tokens are returned. If you keep refreshing with an older token, your next refresh can fail with invalid_grant.
This is also the most common failure mode when teams run token refreshes in multiple processes/containers without proper locking: one process stores the “new” refresh token, another process overwrites it with the stale one, and suddenly every refresh starts failing.
Token expired due to Airtable’s refresh-token lifetime
Airtable refresh tokens are valid for 60 days. If a refresh token is not used within that window, the authorization is effectively revoked and the user must re-authorize. This shows up as invalid_grant on refresh.
Refresh request rejected (400/401) → token revoked
Airtable explicitly revokes refresh tokens when a refresh request is rejected (for example, when the server returns 400 or 401). Common reasons:
- The refresh token is stale because it was already rotated.
- The refresh token was retried after the grace period for duplicate refreshes.
- The request used wrong client credentials (often after a client secret rotation).
Refresh token revoked by Airtable security rules
Even if your token is “recent,” Airtable can revoke refresh tokens under its OAuth safety rules (including the 400/401 rule above). Once revoked, the only fix is re-authentication.
Refresh-token concurrency bugs (race conditions)
Refresh tokens become tricky at scale because token refresh is triggered by many events:
- scheduled syncs
- webhooks
- user-triggered “sync now”
- background retries after 401s
If two workers refresh the same Airtable connection at the same time, you can get a race:
- Worker A refreshes and receives a new refresh token
- Worker B refreshes with the now-stale token and gets
invalid_grant(or worse: succeeds later and overwrites state)
This class of bugs is subtle, sporadic, and highly load-dependent.
How to fix it (production checklist)
1) Confirm you’re using the latest refresh token
If Airtable returns a new refresh_token on refresh, always persist it and use that value for the next refresh. Airtable invalidates previous refresh tokens as soon as a new one is issued.
Fix:
- Store the latest
refresh_tokenreturned by Airtable every time you refresh. - Update the stored refresh token immediately after each refresh (see concurrency section below).
2) Verify your refresh request is correct
Double-check the basics:
grant_type=refresh_token- Content-Type is
application/x-www-form-urlencoded - Authorization uses Basic Auth (
client_id:client_secretbase64-encoded) only if your integration has aclient_secret(Airtable says this header is required when aclient_secretexists, and forbidden when it does not) - You’re hitting the correct token endpoint:
https://airtable.com/oauth2/v1/token
3) Eliminate refresh concurrency (single-flight + locking)
If you run multiple workers, you need to treat “refresh token per connection” as a shared resource.
At minimum, ensure:
- Only one refresh can run for a given connection at a time (distributed lock or single-flight)
- Other requests wait for the in-flight refresh and then use the newly stored access token
- Updates to
(access_token, refresh_token, expires_at)happen atomically
Rather not build this yourself? Nango (open-source OAuth) includes refresh concurrency controls. Your app just needs to fetch the latest access token before each Airtable API call.
4) If it’s truly invalid/expired/revoked: trigger re-auth (don’t keep retrying)
After you’ve ruled out rotation and credential issues, treat invalid_grant as a terminal state for that connection.
Practical production playbook:
- Retry once to cover rare partial failures
- If it fails again, mark the connection as “needs re-auth”
- Pause background syncs for that connection
- Ask the user to reconnect Airtable in-product
This keeps retries quiet, avoids wasteful refresh loops, and gives users a clear next step.
How to prevent Airtable refresh token issues
Use this checklist to reduce “why did my Airtable integration break?” tickets:
- Refresh on a cadence
Airtable refresh tokens expire after 60 days of inactivity. A periodic refresh keeps tokens alive. - Persist the rotated refresh token
Treat “save the new refresh token” as mandatory after every refresh. - Stop using old access tokens immediately
Cache invalidation mistakes are a frequent cause of hard-to-debug auth failures. - Make refresh single-flight and atomic
Ensure one refresh per connection and atomic writes of(access_token, refresh_token, expires_at). If you’re unsure, read our blog on How to handle concurrency with OAuth token refreshes. - Watch
invalid_granttrends
A baseline rate is normal at scale, but spikes usually indicate rotation, concurrency, or credential issues. - Invest in a clean re-auth UX
A clear “Reconnect Airtable” flow saves days of back-and-forth with customers.
Let Nango handle refresh for you
Nango is an open-source auth layer that manages OAuth token lifecycles in production:
- Secure storage for access + refresh tokens
- Automatic access-token refresh
- Safe handling of rotated refresh tokens (so you don’t lose the “current” token)
- Concurrency-safe refresh logic (no race conditions across workers)
- Clear signals when a connection needs re-authentication
If you’re building an Airtable integration (or any integration) and you’re tired of token lifecycle edge cases, Nango can run the refresh pipeline for you.
See the setup details and OAuth URLs in the Airtable API integration documentation.

.png)


