← All notes

Access that expires on its own, and nobody is at fault

18 min read

The reports stop arriving on a Tuesday. Nobody notices until Thursday, when somebody goes looking for last week's numbers and finds the folder empty.

The first hour goes into the obvious questions. Did someone leave? No. Did anyone change a password? No. Was the account locked, the card declined, the subscription cancelled? None of it. The person who set the connection up two years ago is still here, still using the same account, still with the same permissions. Everything is exactly as it was on Monday, and the connection is dead.

What happened is that a clock ran out. Not a subscription, not a licence - permission itself. When you connected two systems together, one of them handed the other a form of standing consent, and that consent came with an expiry date printed on it that nobody in your business has ever read.

Those clocks belong to the vendors, and the tool that broke will point you at something else entirely. There is no fault anywhere in the story, which is exactly what makes it hard to find.

Why does a connection expire when nobody touched it?

Because the vendor who issued the permission put conditions on it, and most of those conditions are about time rather than about anybody's behaviour. Google states this as an instruction to whoever builds the integration, in a sentence that is worth reading as a business owner rather than as a developer:

You must write your code to anticipate the possibility that a granted refresh token might no longer work.

A refresh token is that standing consent in its technical form: the thing one system holds so it can keep acting on your behalf without asking anybody again.

That is Google, on using OAuth 2.0 to access Google APIs. The word doing the work is might. Nothing here is a promise that access will be lost on a schedule you can plan around, which is why it does not appear on anybody's calendar.

The page then lists seven reasons. Three of them are somebody deciding something:

The user has revoked your app's access.

The user changed passwords and the refresh token contains Gmail scopes.

If an admin set any of the services requested in your app's scopes to Restricted...

The other four are conditions that arrive on their own:

The refresh token has not been used for six months.

The user account has exceeded a maximum number of granted (live) refresh tokens.

The user granted time-based access to your app and the access expired.

And, for connections to Google Cloud services, a session length set by an administrator that "could have been exceeded".

Read the second group again as a business owner. Six months of not being used. A count that went one over. A duration agreed at the beginning that has now elapsed. Nobody in your business does any of those; they happen to you.

The other half of the story is what the connection experiences at that moment, because it shapes what your tool shows you. Google's documentation for server-side applications names the error - invalid_grant - and describes it plainly: on refresh, "the token may have expired or has been invalidated. Authenticate the user again and ask for user consent to obtain new tokens." There is no separate signal for "this expired because six months passed" as against "this expired because the user revoked it". One code covers every reason on that list, and whatever is listening receives it with nothing attached to say which.

Where does a seven-day expiry come from?

There is one clock in particular that catches small businesses, and it starts running when somebody leaves a setting exactly as they found it.

When somebody registers an application with Google in order to connect your systems, that registration carries a publishing status, and one of the available values is "Testing". Moving it on means changing that status, and for a connection that asks for sensitive permissions it also means going through Google's verification. That is paperwork, and paperwork gets skipped when the thing already works. Here is what Google says happens to a connection that stays where it is:

A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days...

The elision at the end covers an exception, and it matters: connections that ask only for basic identity details - name, email address, profile - are not caught by this. A connection that reads your Drive, sends from your mailbox or writes to your calendar is.

Seven days. Not seven days from the moment somebody clicked something wrong; seven days from every single re-authorisation, forever, until the registration leaves Testing. Google's own page on production readiness confirms the rule from the other direction, when it describes what a Workspace administrator can override: "This status overrides certain standard OAuth limitations for the organization's users, such as the 100-test-user cap and the 7-day refresh token expiration limit for apps in the Testing status."

The reason this is worth a section of its own is the shape of the mistake. Nobody chose a seven-day expiry. Somebody built something, it worked, and they moved on to the next thing, and the default they left behind quietly became a weekly maintenance job for whoever inherits the business process.

The limit that fires without warning

Some clocks are not clocks at all but counters, and this one deserves naming because Google uses an unusually direct phrase about it:

There is currently a limit of 100 refresh tokens per Google Account per OAuth 2.0 client ID. If the limit is reached, creating a new refresh token automatically invalidates the oldest refresh token without warning.

"Without warning" is Google's wording, not a characterisation. And the mechanism is worth understanding, because it is the one case where the thing that kills your connection is you being conscientious. Every time somebody reconnects an account - after a glitch, during testing, while a contractor sets up a second environment - a new grant is issued. When the hundredth is issued, the first one stops working.

One connection, set up once, never comes near a hundred. Three people reconnecting the same accounting account over two years, each time to make something work, can get there between them - and the failure lands on whichever connection was set up first and has been running quietly ever since.

How long does each vendor's permission last?

The clocks are published. They are simply published in the developer documentation of eight different companies, in eight different places, in the units each company happened to choose. Collected together, they look like this.

Vendor The published clock What the page says resets or triggers it
Google 7 days for apps left in "Testing"; six months if unused; oldest grant dropped past 100 Publishing status, disuse, or reconnecting too often
Microsoft Entra ID "90 days for all other scenarios", 24 hours for apps that run entirely in the browser Not stated on the page
Intuit QuickBooks Online "Refresh tokens have a rolling expiry of 100 days" Last use, rolling forward
Xero "Refresh tokens expire after 60 days" Not stated on the page
Salesforce Default is valid until revoked; the publisher of a connected app can enforce a 30-day idle limit A setting made outside your business
Slack 12 hours, but only if token rotation is enabled Turning rotation on
Dropbox None documented -
Zoho "This token won't expire." -

Two rows are worth pausing on. Xero adds a detail that turns a good day into a bad one: after a connection refreshes itself, the old permission stays usable "for a grace period of 30 minutes. After 30 minutes your previous refresh token will expire and the user will need to re-authorise your api application ...". So a connection that renewed itself successfully but failed to write down the result has half an hour of life left, and then needs a human.

Slack's is the opposite kind of trap. Token rotation is a security feature you switch on deliberately, and Slack is honest about what it costs: "Without token rotation, the access token never expires. With token rotation, it expires every 12 hours." Directly under that, in a callout: "Token rotation may not be turned off once it's turned on". A one-way door, clearly signposted, in documentation your business will never see because the person who read it was doing something else that afternoon.

Which of your connections has a clock on it, and what the day it runs out would cost you - that is the first half of the process audit: what can be automated, in what order, and what each piece is worth, in writing, in three business days.

A clock can be installed by somebody you have never met

Not every clock is set by the platform you signed up to. Some are set by whoever published the piece of software sitting between you and it, and they take effect in your account without your account being asked.

Salesforce lets an administrator set a policy on how long a connected application's permission survives without use. The option is called "Expire refresh token if not used for", followed by a number of days, and Salesforce explains it like this: "The refresh token is valid as long as it's been used within the specified amount of time. For example, if set to seven days, and the refresh token isn't exchanged for a new session within seven days, the next attempt to use the token fails." The default is a different option, described as valid until revoked, under which the permission is used indefinitely unless somebody withdraws it.

Then comes the part that belongs in this article rather than in a security guide. Salesforce also lets the publisher of a connected app enforce an idle limit on everybody who installs it - "As an app developer, when you turn on this limit, it affects refresh token policies for your subscribers" - and its documentation describes what that does to a permission which was deliberately set never to expire:

This policy is no longer valid with the idle TTL limit enforced. In the UI, this option becomes hidden and the policy selection changes to "Expire refresh token if not used for specific time" with the validity period set to 30 days.

The setting that said "never expire" does not warn, argue or ask. It becomes a different setting, the old option disappears from the screen, and every quiet connection through that app acquires a thirty-day fuse. The developer who turned the limit on was improving security and was right to. Nobody in that sequence did anything wrong, and a month later something stops - in a business that was never part of the decision.

This is the same shape of problem as an automation that runs on one person's account, with the human element taken out. There, the risk is that the access belongs to somebody who might leave. Here, everybody stays and the access leaves on its own.

Why does the tool blame a password change?

Because the tools describe the causes their support teams see most often, and those causes are human. Zapier's help page on app connections explains expiry like this:

Expired app connections: You must reconnect your app connection if your password changed recently or if your organization enforced additional security controls.

Both of those are real. Neither of them is the calendar. At nine in the morning, with a broken connection already in front of you, that sentence buys twenty minutes of establishing that nobody changed a password and nobody enforced anything - and ends with the reader more confused than they started, because the one explanation on offer has been ruled out and no other has been offered.

The wording is accurate as far as it goes. The trouble is where the knowledge lives. The clock is documented by the vendor who issued the permission, in developer documentation. The failure is displayed by the tool that used the permission, in help documentation. Nobody owns the sentence that would connect the two, which is roughly: this can also simply have run out, and here is the schedule.

Who gets told, and how long after the failure?

Somebody does get told, in most cases. The question worth asking is who, and at what point in the sequence.

Make sends an email when a scenario fails and nothing catches the error - its documentation says that "When errors are not handled by any error handler, Make sends you an email notification:", and lists connection changes among the causes: "An error may occur due to changes in the connection, such as expired API keys, unavailable APIs, or revoked access after team or permission changes." That notice arrives after the first failure. Not before the expiry - there is nothing to notify about before the expiry, because from the platform's point of view nothing has happened yet.

Zapier's documented behaviour is worth reading closely if you are on one of the cheaper plans, because the safety net is priced:

Your Zap will automatically turn off if 95% of its runs result in errors in the last 7 days.

If your account is on a Team or Enterprise plan, Zapier will send you an email notification to the account owner and provide a grace period before turning off your Zap. Enterprise plan accounts have a 72-hour grace period and Team plan accounts have a 24-hour grace period.

The advance email and the grace period are documented for Team and Enterprise. For plans below that, the page documents the automatic switch-off and does not document a warning. So the sequence for a small business is: permission expires, the automation errors, it keeps erroring for up to a week, and then it turns itself off - and the moment when somebody notices is determined by how visible the output was. Nobody misses a folder for a fortnight, so a connection that only files documents can be dead that long. This is the everyday version of the automation failure nobody was told about.

There is one clock that does come with a warning, and it deserves credit. Google deletes application registrations that have gone unused: "OAuth 2.0 clients that have been inactive for six months are automatically deleted", and once that happens, "Calls to Google APIs using existing access tokens or refresh tokens associated with the deleted client will fail." Before deleting, Google writes: "You will receive an email notification 30 days before an inactive client is scheduled for deletion." Thirty days is generous. The page does not say whose address that is. Whoever registered the project is the likely answer, and in a small business that is often a contractor who finished the engagement eighteen months ago.

The connection that runs daily is the safe one

Several of these clocks measure idleness rather than age, and that inverts the intuition about which of your automations is at risk.

Intuit's documentation for QuickBooks Online states it in one line - "Refresh tokens have a rolling expiry of 100 days" - and spells out the consequence: "If 100 days pass, or your refresh token expires, users need to go through the authorization flow again and reauthorize your app." Rolling means the hundred days restart each time the connection is used. A sync that runs every night will never reach day one hundred. A quarterly VAT export, a year-end reconciliation, a report that only runs when somebody asks for it - those live entirely inside the danger zone.

Google's six-month rule works the same way, and so does the Salesforce idle limit

  • the time a permission may sit unused before it lapses - which its documentation describes as "a sliding window: each time the token is used within the 30 day-period, its idle TTL resets."

Put together, this produces a rule of thumb that is uncomfortable but reliable: the automations you rely on most are the ones least likely to fail this way, and the ones you rely on rarely are the ones that will fail exactly when you finally need them. The quarterly export dies in the quarter you did not run it, and you find out on the day of the deadline.

It is also the argument for keeping a register of what is automated with a column most registers do not have: how often this thing actually runs.

The people who connect things themselves keep finding this out

The clearest evidence that this is a structural problem rather than a configuration mistake is that the same question keeps being asked, by people who followed the setup steps exactly and still ended up with a connection that had to be rebuilt on a schedule.

On the n8n community, 8 May 2026: "Anyone found a solid fix for Google credentials (Sheets, Gmail, Drive) needing to be re-authorized often? Refresh tokens seem to drop, especially on workflows that don't run constantly."

That last sentence is the whole article in the words of somebody who found it out the hard way.

Which of these clocks is not running for you?

It would be easy to leave the impression that all standing permissions expire. They do not, and the exceptions are documented as clearly as the rules.

Dropbox tells developers what happens when an access token expires and then adds the part that matters here: "A user's approval remains valid until explicitly revoked." Zoho's documentation, describing the same kind of credential, says plainly: "This token won't expire." Salesforce's default policy, before anybody changes it, is permission that lasts until it is revoked.

Every one of those deserves a silent "for now", and that is the honest position for a business owner to adopt about all of this. Today's answer is not a guarantee about next year's. Slack's rotation is the proof: an installation whose access "never expires" turns into one that expires every twelve hours the moment somebody enables a feature, and cannot be turned back.

So the useful question is not "do permissions expire" but "which of mine do, and what is on the other end of each one".

What should you check in your own setup?

Five things, none of which requires a developer, and all of which are questions rather than tasks.

  1. List the connections, not the tools. Two systems joined together is one connection with one permission behind it. Most businesses can write the whole list on half a page and have never done it. If you have a handover checklist from whoever built your automations, the list may already be in it.
  2. Mark how often each one actually runs. Anything that runs less than monthly goes in a separate group. That group is where idle expiry lives, and it is also the group nobody monitors, because nothing is expected from it most of the time.
  3. Ask whose account each one was authorised with, and whether that person still works here. This is the older question, and it is a different one from this article's, but it is answered by the same half page of notes.
  4. For anything connected to Google, ask whether the registration behind it is still in "Testing". You do not need to inspect it yourself. The question to put to whoever built it is exactly that sentence, and a connection that has needed re-authorising roughly every week for months has already answered it.
  5. Find out where the failure notice goes. Not whether one is sent - who receives it. If the answer is an address at a company you no longer work with, or a shared inbox nobody reads, the notification exists on paper only.

Nothing on that list prevents an expiry. The clocks belong to the vendors and they will keep running. What the list changes is the gap between the moment a permission runs out and the moment somebody in your business knows, and that gap is the entire cost of the problem.

When this stops being a settings question

For one connection, this is housekeeping. Somebody reconnects an account every few weeks, grumbles, and gets on with the day.

It stops being housekeeping at the point where you cannot say out loud how many connections your business runs on, or what each one would cost you on the day it quietly stops. Permissions are the small half of that. The work has grown past the map anybody is holding, and the connections are simply where you noticed.

If you would rather have somebody map what your business actually runs on and work out what can be automated, in what order, and what each piece is worth, that is the process audit. $299, three business days, and a written map you keep whether or not you hire us.