shaunchander.me
09/02/26 · 3 min · Tooling

Giving Hermes an evergreen Google token

Part of my second brain is an agent that runs on Hermes, and one of its jobs is pulling context out of my Google Calendar and my email so I don’t have to go fetch that stuff myself. It’s genuinely one of my favorite parts of the whole setup, but I keep facing a problem with it.

It disconnects all the time.

Every week or so, Hermes would just stop being able to talk to Google. The token it was using would expire, I’d have to go through the whole OAuth dance again, and then everything would work great… for about another 7 days. Rinse and repeat.

The problem

For a while I assumed the bug was on my end, because that’s usually where the bug is. I figured my refresh logic was broken, or I was storing the token wrong, or some scope was misconfigured somewhere.

Nope. The actual cause was way dumber and way simpler: I never published my OAuth app to production in GCP.

When you set up an OAuth consent screen in Google Cloud, it starts out in Testing mode. And Google has a documented (but easy to miss) behavior here: any refresh token issued by an app in Testing mode expires after 7 days. Doesn’t matter how well-behaved your refresh logic is, because Google is just going to invalidate the token on schedule and make you re-consent.

So my “bug” was really just Google doing exactly what it said it would do, and me never reading the fine print.

The fix

The fix is to flip your app over to production mode, because production apps get long-lived refresh tokens that don’t expire on a timer. As long as you keep using the token, it basically lives forever.

Before Google lets you publish though, you need to have a few things in place:

  1. An app logo. Any reasonable image works, I just exported a little mark for Hermes.
  2. A valid privacy policy and terms of service page. These need to be real, live URLs. I threw up generic ones on this very site at shaunchander.me/privacy and shaunchander.me/tos, and honestly writing generic boilerplate for a personal tool took all of a few minutes with AI.
  3. A verified domain. Your homepage, privacy policy, and TOS links all need to live on a domain you’ve verified with Google (through Search Console), so Google can actually index the pages and confirm you own the thing you’re pointing at.

Once you have those, head into your GCP project, go to the OAuth consent screen settings (Google has been rebranding this area as the “Google Auth Platform”, so the exact navigation shifts around a bit), fill in the branding fields with your logo and URLs, and hit publish.

Note: After publishing, you’ll need to re-authenticate one more time. Tokens minted while you were in Testing mode keep their old 7-day lifespan, so you want a fresh one issued under production.

The whole thing, from filling out branding to Google accepting it, took me somewhere around 5 to 10 minutes. And that’s it. One last OAuth dance and the token is now evergreen. Hermes hasn’t dropped its connection since.

A quick note on scopes

One thing I want to call out is that I keep Hermes on a pretty short leash. It only gets two scopes: Google Calendar and read-only Gmail. The token could absolutely do more (send email, edit events, the whole nine yards), but I don’t need any of that, so I don’t grant any of that.

This is just basic least-privilege thinking, and it matters a bit more here because this token now lives forever. An evergreen token that can only read is a much smaller thing to worry about than an evergreen token that can act on my behalf.

So if your personal Google integration keeps mysteriously dying every week, go check your consent screen. You’re probably still in Testing mode, and ten minutes in GCP will fix what no amount of debugging your refresh logic ever will.

© 2026 · brooklyn, ny 3:44 PM