AI Tool Pipelines — Automate Your WorkflowsAI Tool Pipelines

Refresh Tokens vs API Keys: Handling OAuth2 Expiry in Automations

6 min read · Updated Aug 5, 2026

Hand holding a smartphone with a stopwatch app running, representing a limited-lifetime access token

An OAuth2 access token expires, usually in under an hour, by design, so it cannot sit around as a long-lived secret the way an API key does. A refresh token is the separate, longer-lived credential your automation stores and uses to silently get a new access token when the old one expires, without asking the user to log in again. Handling this correctly in an automation pipeline means storing the refresh token securely, catching a 401 from an expired access token, exchanging the refresh token for a new access token automatically, and knowing what to do when the refresh token itself has been revoked or expired.

Key takeaways

  • An access token is short-lived by design, often 30 to 60 minutes, limiting the damage window if one leaks.
  • A refresh token is longer-lived (days, weeks, or indefinite depending on the provider) and exists specifically to get a new access token without repeating the full user consent flow.
  • In n8n and most automation tools, a 401 mid-workflow on a credential that "worked yesterday" is almost always an expired access token, not a broken integration. Refresh automatically and retry once before treating it as a real failure.
  • Some providers revoke a refresh token after a fixed period of inactivity, or after the user revokes access manually, which a silent refresh cannot fix. Only re-authentication can.
  • Never treat a refresh token like an API key. It should trigger a specific "get a new access token" code path, never be sent directly as if it were a bearer credential on a normal API call.

Why the access token expires and the refresh token does not

The access token is what actually goes on every API request, which makes it the credential most exposed to leaking, through logs, through a debugging session, through a misconfigured error message. Keeping its lifespan short limits how much damage a leaked one can do. The refresh token, by contrast, is only ever sent to the provider’s token endpoint, never to the third-party API you are actually calling, so it has a much smaller exposure surface and can safely live longer. That asymmetry, short-lived and widely used versus long-lived and narrowly used, is the entire design logic behind having two tokens instead of one.

The refresh flow, end to end

When the access token expires, your server exchanges the stored refresh token for a new access token, and often a new refresh token as well, depending on the provider.

bash
curl https://oauth.example.com/token \
  -d grant_type=refresh_token \
  -d refresh_token={{STORED_REFRESH_TOKEN}} \
  -d client_id={{CLIENT_ID}} \
  -d client_secret={{CLIENT_SECRET}}
Exchanging a refresh token for a new access token.

Catching expiry in an automation pipeline

Wrap every OAuth2-authenticated call with a check for a 401, refresh once, retry once. Anything beyond one retry after a refresh usually means the refresh token itself is no longer valid, not that the timing was unlucky.

javascript
async function callWithAutoRefresh(fn, credentials) {
  try {
    return await fn(credentials.accessToken);
  } catch (err) {
    if (err.status !== 401) throw err;

    const refreshed = await refreshAccessToken(credentials.refreshToken);
    if (!refreshed) {
      throw new Error('Refresh token invalid, re-authentication required');
    }

    await saveCredentials(refreshed);
    return fn(refreshed.accessToken);
  }
}
Refreshing automatically on a 401, then retrying the original call exactly once.
A person typing on a keyboard in a modern tech workspace, building automated token refresh logic

The four days of silently missing reports

In September 2023, a workflow I built for a marketing ops team pulled data from a connected Google account every morning at 6 a.m. through n8n. Six weeks in, it started failing silently, not with an error node triggering, but with an empty result set that nobody noticed for four days. The access token had expired overnight, and the custom HTTP Request node calling an endpoint n8n had no native node for was passing the stale token directly with no refresh logic in front of it, so every request came back with a 401 that fell into an unguarded branch treated as "no data today" instead of a real error. Adding the automatic refresh-and-retry pattern above fixed the workflow permanently. Reconstructing four days of missing reports by hand was the least enjoyable part of that week.

Vibrant abstract digital art in red, green, and blue displayed on a monitor screen

Side by side

Access token and refresh token, compared directly.
FactorAccess tokenRefresh token
Typical lifespan30 to 60 minutesDays to indefinite, provider-dependent
Sent toThe third-party API on every requestOnly the provider’s own token endpoint
PurposeProves the current request is authorizedGets a new access token without user interaction
What expiry meansRefresh automatically, usually invisible to the userFull re-authentication required, user sees the login screen again

I think the most common automation bug involving OAuth2 is not a security bug at all, it is teams treating "connected" as a permanent state after the initial consent screen, when it is actually a lease that needs active renewal. n8n’s built-in OAuth2 credential type handles refresh automatically for you inside its native nodes, which is exactly why this pain shows up almost exclusively in custom HTTP Request nodes calling an API n8n has no dedicated node for, where nobody wired up the refresh step by hand.

Google’s OAuth2 documentation (accessed 2025) states that access tokens typically expire in one hour, and that a refresh token can itself be revoked after roughly six months of the associated app going unused. That second detail matters for any automation that runs infrequently: a workflow that only fires once a quarter can find its refresh token has quietly expired between runs, with no error until the very next attempt.

“Connecting an account is not a one-time event. It is a lease, and leases expire whether or not you were watching.”

Frequently asked questions

Frequently asked questions

What is the difference between an access token and a refresh token?

An access token is the short-lived credential sent with every API request to prove the current session is authorized. A refresh token is a longer-lived credential used only to obtain a new access token when the old one expires, without asking the user to log in again.

Why does an access token expire so quickly?

Because it is the credential most exposed to leaking, sent on every single API call, potentially logged, cached, or exposed in debugging. A short lifespan limits how much damage a leaked access token can cause before it stops working on its own.

What happens when a refresh token itself expires or gets revoked?

The automated refresh silently fails, and there is no way around it programmatically. The user has to go through the full OAuth2 consent flow again to reconnect the account, which is why a pipeline should surface this clearly rather than retrying forever against a dead refresh token.

How do I handle token refresh automatically in n8n?

n8n’s built-in OAuth2 credential type handles refresh automatically for any of its native nodes. For a custom HTTP Request node calling an API without a dedicated n8n node, you need to wire up the refresh-on-401 logic yourself, since it is not automatic outside the native credential system.

Is a refresh token as sensitive as a password?

It is arguably more sensitive in an automation context, since it can silently mint new access tokens indefinitely until revoked. Store it encrypted, never log it, and never send it anywhere except the provider’s own token endpoint.

Why did my automation that "worked yesterday" suddenly fail with a 401?

Almost always an expired access token, not a broken integration or a revoked permission. Add automatic refresh-and-retry logic in front of the call, and only treat a 401 as a real failure if it persists after a successful token refresh.