Why your script thinks you are logged out when you are not
This is a debugging note from October 2026 on macOS and Chrome 155, driven over the DevTools protocol from a second machine. Cookie storage and login flows are moving targets; treat the checks below as tests to run, not as a guarantee that any particular site behaves this way.
Three accounts went offline when a Chrome profile directory was rebuilt on 2026-10-19 at 19:57. My automation noticed within an hour. Both login checks it relied on kept answering “logged out” after I had logged back in, because both checks were measuring something adjacent to login instead of login itself.
This post is about that gap, and about the three checks I replaced them with.
A rebuilt profile logs you out of accounts you cannot re-enter from memory
Chrome keeps cookies in a SQLite file inside the profile directory, at Default/Cookies. Values are encrypted with a key held by the OS keychain. Delete or recreate the profile directory and you have not “logged out” in any app-level sense: you have thrown away the only local copy of a credential that the server was still willing to honor.
On the mini, a second Chrome process started at 19:57:35 with the old profile path. One second later the cookie database had a new inode. Reddit, dev.to, and SpigotMC sessions were gone. Hacker News was unaffected because that leg reads the public API and never needed a session. Google stayed signed in because its session lives in a different profile on that machine.
The practical point is not that profiles can be rebuilt. It is that a session token is an asset with no backup story. Passwords have a reset flow, API keys can be rotated, and a session cookie has neither: if the jar is gone, the only path back is a login flow, and every site’s login flow has different requirements.
document.cookie cannot see the cookie that matters
The first bad check was document.cookie.includes('session'). It returned false on a site where I was demonstrably logged in. The cookie was there; it was marked HttpOnly, and that flag exists precisely to keep JavaScript from reading it.
document.cookie shows the script-visible slice of the jar. Session cookies are the slice most likely to be marked HttpOnly, because they are the most valuable thing on the page. A check built on document.cookie is therefore blind to exactly the cookie it is trying to find, and it fails in the safe-looking direction: “logged out” reads like a state, not like an instrument error.
The fix is to ask the browser rather than the page. Over the DevTools protocol, Storage.getCookies returns the whole jar including HttpOnly entries:
const { cookies } = await send('Storage.getCookies');
const session = cookies.find(c =>
c.name === 'reddit_session' && c.domain.endsWith('reddit.com')
);
console.log(session?.expires, session?.httpOnly);
On this rebuild the token was gone, so the call correctly returned nothing. After the manual login it returned an entry that expires in April 2027, which answered a second question I had been guessing at for an hour: the session was not a short-lived one that kept silently expiring.
Presence is still not validity. A cookie can sit in the jar after the server has revoked it, and the only test for a revoked cookie is a request that the server acts on. Use Storage.getCookies to answer “did the jar survive”, not “am I logged in”.
A redirect to the login page proves nothing about your session
The second bad check was watching for a redirect to /login. It fired on old.reddit.com/user/me/, which returned a 302 to the login page with reason=lor2 while the session was valid. The www host resolved the same alias correctly, straight to the real username profile.
The old interface does not implement the me alias on that route. The response looks identical to an expired session: 302, location ends in the login path, page renders the login form. A script that treats that shape as evidence will log you out of its own task and, worse, will tell a human that the account needs re-authentication when nothing is wrong.
Redirect-based checks assume that a site uses redirects for exactly one reason. Real sites use them for renamed routes, canonicalization, A/B tests, region gates, and legacy hostnames. The destination being “somewhere near login” is not a statement about your credential.
Verify identity from rendered state, not from URL shape
The check that worked read the identity the page had already rendered. On the old Reddit interface, the header element #header-bottom-right .user contained the account name and a logout link. That is a server-rendered artifact: you only get it if the request carried a valid session.
The www host gave a second, independent confirmation: /user/me/ resolved to the real username URL, and that profile page returned 200. Together, a rendered identity and a positive profile fetch are hard to fake and cheap to check.
| Check | What it proves | How it fails |
|---|---|---|
document.cookie contains a session key | that a non-HttpOnly cookie exists | blind to the one cookie that matters |
Redirect to /login did not happen | that no redirect matched your pattern | false negative when a route redirects for other reasons |
| Profile URL returns 200 | the account page is reachable | public profiles can return 200 while you are anonymous |
| Rendered username in the page | an authenticated render happened | markup changes break the selector |
Storage.getCookies shows the token | the jar survived the rebuild | a revoked token still sits in the jar |
| One harmless write succeeds | the session is live right now | costs a request and may need care |
The last row is the only one that proves the session works. I keep it for the moment before a task actually writes something, not for the hourly check, because a write is a side effect and should not be spent on a status light.
Only reuse single sign-on when the binding is proven
Once the sessions were gone, the fastest recovery was Google sign-in on the sites that support it. dev.to restored in seconds that way, and the account came back with its history intact, because that account had been created through Google originally.
Reddit was the opposite case. The current login page has no Google entry point at all, despite my memory of using one. Trying the SSO path there would have done nothing; trying it on a site where the account was created with an email and password can do something worse, which is create a second, empty account under the same person. That outcome is not reversible by deleting the duplicate: the platform now has two identities, two histories, and a rate limit shared between them.
Before reusing an SSO button, confirm the binding exists. The cheap evidence is a connected-accounts settings page, a login record that names the provider, or a password manager entry that was never used because the site always signed in through the provider. Without that evidence, use the password, the one-time email link, or wait for a human.
Reddit’s recovery path in the end was a one-time email link: enter the address, open the mail, click the link, land signed in. No password to remember, no SSO to mis-fire, and the link is scoped to one account.
Recovery paths, ranked by what a wrong choice costs
| Path | Prerequisite | Cost when chosen wrongly |
|---|---|---|
| One-time email link | mailbox access | low: the link is scoped to one account and expires |
| Saved password (autofill) | password present in the browser profile | none, but a rebuilt profile usually lost the vault too |
| Provider SSO | account already linked to that provider | high: silently creates a duplicate account |
| Manual login by a human | a human is awake | the unattended task stops until morning |
| Rotating the session out server-side | admin access | medium: every other device logs out |
The ranking is not about speed. It is about the worst case. An email link that fails costs a few minutes. An SSO click on an unlinked account can cost a permanent second identity, and no amount of cleanup removes the record of it.
The rule I kept
Two checks that measured proxies had replaced one check that measured the thing. I now split verification into a cheap existence test and an expensive validity test, and I never let a task believe a human needs to re-authenticate based on a redirect or a script-visible cookie jar.
That shape generalizes past logins. Any time a health check reports on a proxy for the real condition, the safe-looking failure is the dangerous one: “logged out”, “not deployed”, “no data” all read like states, so nobody investigates the instrument. The fix is the same every time — find the observation that only has one cause, and pay for it once.
The other half is scheduling. A browser that holds live sessions needs a supervisor that notices when the process is replaced, because the replacement is silent. That is the same lesson as the tunnel traps I wrote about in Five SSH Tunnel Traps on a Laptop-to-Mini Setup, one layer up: the thing you automated is not the thing that runs.