
Why do OAuth refresh tokens keep breaking in production when we connect AI features to third-party apps?
Most teams only notice their OAuth refresh token problems once the AI feature has “worked in staging” and completely falls apart in production. Everything looks fine in the sandbox, then a week after launch: 401s everywhere, users randomly de-auth, security gets nervous, and your agent quietly regresses back to a chat-only toy.
Quick Answer: OAuth refresh tokens usually break in production because of subtle differences between staging and live environments: misconfigured redirect URIs, wrong token lifetimes, missing scopes, rotation rules, or multi-user edge cases that only show up at scale. For AI features, the pain compounds when you mix long-running agents, service accounts, and poor token storage with provider-specific rules (looking at you, Google).
Below is a focused FAQ on why this happens, how to debug it, and how to stop refresh tokens from owning your roadmap—especially when your AI agent is calling Gmail, Calendar, Slack, Salesforce, and other third-party APIs.
Quick Answer: OAuth refresh tokens usually break in production because of subtle differences between staging and live configs, provider-specific policies, and multi-user edge cases that only appear at scale. Without robust token storage, rotation handling, and clear authorization boundaries, your AI features end up fragile and hard to debug.
Frequently Asked Questions
Why do OAuth refresh tokens work in staging but break in production?
Short Answer: Your staging and production environments don’t actually match—redirect URIs, client IDs, secrets, scopes, and token lifetimes are slightly different, and those differences only show up once real users and real traffic hit the system.
Expanded Explanation:
In staging, you usually have a single developer test account, minimal traffic, and a clean OAuth app configuration. In production, you introduce:
- Different OAuth client IDs/redirect URIs
- Different domain and cookie settings
- Real-world user behavior (revoking access, changing passwords, org policy updates)
- Provider policies that only apply to “in production” apps
This means the same refresh logic that “worked fine” in staging suddenly starts failing with invalid_grant errors, silent revocations, or token lifetimes that don’t match your assumptions. AI features make this worse because agents may try to use refresh tokens hours or days after they were issued, across multiple tools and users.
Key Takeaways:
- Treat staging and production OAuth apps as separate systems with separate configs.
- Assume production token behavior (lifetimes, revocation, security policies) will differ from staging.
How do OAuth refresh tokens actually work for long-running AI features?
Short Answer: The client exchanges a short-lived access token for a long-lived refresh token, then periodically uses that refresh token to get new access tokens—until the refresh token itself is revoked, rotated, or expires based on provider policy.
Expanded Explanation:
A typical flow for AI features that call third-party APIs looks like:
- User signs in and approves scopes via OAuth (e.g., Gmail, Calendar).
- Your backend receives an authorization code and exchanges it for:
- An access token (short-lived: minutes to an hour)
- A refresh token (long-lived: days to indefinite, depending on provider)
- Your AI agent uses the access token to call APIs (send email, create events, post to Slack).
- When the access token expires, your backend uses the refresh token to get a new access token.
For long-running agents, the refresh step becomes critical. If you mis-handle storage, rotation, or revocation, your agent suddenly loses the ability to act on behalf of the user, often mid-conversation or mid-workflow.
Steps:
- Securely store the refresh token server-side (encrypted at rest, never exposed to the LLM).
- Implement a robust refresh flow that handles rotation (providers may issue a new refresh token).
- Detect and gracefully handle invalid or revoked refresh tokens, prompting the user to re-auth.
What’s the difference between access tokens and refresh tokens, and why does it matter for AI features?
Short Answer: Access tokens are short-lived and used directly on APIs; refresh tokens are long-lived and used only to get new access tokens. For AI features, using access tokens incorrectly (storing them in the wrong place, exposing them to the model) or assuming refresh tokens never change is a recipe for production failures.
Expanded Explanation:
Access tokens and refresh tokens serve different roles:
-
Access tokens:
- Short-lived (e.g., 1 hour).
- Passed to Gmail/Slack/Salesforce APIs as
Authorization: Bearer <token>. - Should never be stored in the LLM context or logs.
-
Refresh tokens:
- Longer-lived, but not immortal.
- Never sent to the resource APIs—only to the OAuth provider’s token endpoint.
- Subject to rotation and revocation rules.
For AI agents, this separation is crucial. The model decides what to do (send email, create calendar events). The runtime decides how to do it, including securely injecting access tokens at call time. If you blur these responsibilities—e.g., passing tokens into prompts—you not only risk security incidents but also increase the chances of brittle token behavior in production.
Comparison Snapshot:
-
Option A: Treat tokens as generic strings in your agent
- Tokens end up in prompts, logs, or client-side code.
- Hard to rotate, hard to debug, easy to leak.
-
Option B: Enforce a clear token boundary in your runtime
- LLM never sees tokens (“zero token exposure to LLMs”).
- Refresh logic is centralized and tested.
- Easier to handle provider quirks consistently.
-
Best for: Production AI agents that need to act across Gmail, Calendar, Slack, GitHub, Salesforce with user-specific permissions and predictable behavior.
How can we stop refresh tokens from randomly breaking our AI integrations in production?
Short Answer: Centralize your OAuth handling, store refresh tokens securely, implement rotation-aware refresh logic, and treat re-auth as a first-class path—not an edge case.
Expanded Explanation:
Most AI teams fall into the “just make it work” trap: they bolt OAuth flows onto the side of their agent and hope refresh tokens last forever. In reality, you need:
- A single auth service (or runtime) responsible for:
- Starting OAuth flows
- Exchanging codes for tokens
- Storing/rotating/refreshing tokens
- Emitting clear errors when re-auth is required
- A contract between your agent and the runtime: tools that represent actions (e.g.,
Google.SendEmail,Google.CreateEvent,Slack.PostMessage) with the auth boundary enforced underneath.
Arcade’s MCP runtime does exactly this: agents call tools, Arcade handles secure OAuth 2.0 flows with scoped access, token persistence and refresh, and zero token exposure to LLMs. The agent never juggles refresh tokens; it just asks to “send this email” and the runtime either does it with the right user permissions or returns an auth error you can handle.
What You Need:
- A dedicated backend or MCP runtime that:
- Uses industry-standard OAuth 2.0 with scoped access.
- Handles token storage, refresh, and rotation out of band.
- Tool definitions that keep tokens out of prompts and focus on the action (send email, create event, update CRM).
Strategically, how should we design our AI architecture so OAuth refresh tokens don’t own our roadmap?
Short Answer: Treat authorization and tool execution as core infrastructure, not one-off glue code. Build (or adopt) a runtime where agents act with user-specific permissions and tokens are managed centrally with clear governance.
Expanded Explanation:
If you’re bolting OAuth directly into each AI feature, you’ll keep re-learning the same painful lessons:
- Service accounts don’t match real user permissions.
- Refresh tokens behave differently across providers.
- Security reviews bog down when there’s no clear auth model.
- Debugging 401s at scale becomes its own backlog.
A more sustainable approach is to design around three principles:
-
User-specific permissions, not service accounts
Your AI agent should act “as the user,” not as a generic bot. That means OAuth flows tied to real identities and scopes that match what the user can actually do in Gmail, Slack, or Salesforce. -
Authorization enforced in code, not prompts
Permission gates, scoped access, RBAC, and audit logs belong in your runtime, not in your system prompt. The agent shouldn’t decide if it’s allowed to send an email; the runtime should. -
Agent-optimized tools, not raw API wrappers
Define tools likeGmail.ListEmails,Google.SendEmail,Slack.PostMessage,Salesforce.UpdateRecordthat encapsulate:- The action.
- The required scopes.
- The auth requirements and token handling.
Arcade’s MCP runtime is built around exactly this model. You get SDK-first auth flows (auth.start, wait_for_completion), out-of-the-box MCP tools for Gmail, Calendar, Slack, GitHub, HubSpot, Salesforce, and more, plus governance: tenant isolation, audit logs, RBAC, SSO/SAML. Tokens are exchanged behind the scenes, never in view of the LLM, and refresh tokens stop being a fire drill.
Why It Matters:
- You ship AI features that keep working weeks and months after launch, not just in the demo.
- Security and compliance teams see a clear authorization model with scoped OAuth, audit trails, and no tokens in prompts.
Quick Recap
OAuth refresh tokens don’t randomly “go bad”—they break in production when assumptions from staging collide with real-world provider policies, multi-user behavior, and ad-hoc token handling. For AI features, the stakes are higher: agents need to send email, manage calendars, post to Slack, and update CRMs as the user, which means long-lived, well-governed authorization.
The fix is architectural: centralize OAuth flows and token management, keep tokens out of your LLM, and expose clean, agent-optimized tools that enforce user-specific permissions. When you do that, refresh tokens become boring infrastructure instead of a recurring outage.