Skip to content

fix(addon): stop closing Send tabs when access token has expired#949

Open
aaspinwall wants to merge 1 commit into
mainfrom
fix/addon-expired-token-closes-send-tabs
Open

fix(addon): stop closing Send tabs when access token has expired#949
aaspinwall wants to merge 1 commit into
mainfrom
fix/addon-expired-token-closes-send-tabs

Conversation

@aaspinwall

Copy link
Copy Markdown
Collaborator

What changed?

Made the add-on's getLoginState() (packages/addon/src/menu.ts) a read-only probe. It now reports logged-in based on a stored session that has a refresh_token, regardless of the OIDC access-token expires_at, and no longer performs destructive side effects. The previously coupled closeAllTbProTabs() / storage.remove / menuLogout() calls were removed from the probe, and the now-unused closeAllTbProTabs() helper was deleted. Added packages/addon/src/test/menu.test.ts covering the behavior, including a regression guard that an expired access token never triggers browser.tabs.remove.

AI disclosure: This change was implemented by Claude (agent-written) under close human direction — the maintainer drove the investigation by reproducing the bug manually in Thunderbird, identified the logged-in vs logged-out asymmetry, reviewed the root-cause analysis, and approved the plan and the final diff.

Why?

Inside Thunderbird, clicking a send.tb.pro link from the accounts.tb.pro/dashboard closed the newly-opened Send tab once the add-on's stored access token had passed its short-lived expires_at. getLoginState() is called by the /send/profile route guard (via GET_LOGIN_STATE) and by a 60s timer; the old code treated an expired access token as logged-out and called closeAllTbProTabs(), which removed every send.tb.pro tab — including the one just opened.

This is a category error: expires_at is the access-token expiry, not the session lifetime. The Send web app refreshes the access token transparently via userManager.signinSilent() using the refresh_token, so an expired access token is not a logged-out state. Genuine logout already flows through the SIGN_OUT path. This is distinct from #945 (the ProfileView self-close), which is working correctly.

Limitations and Notes

  • The add-on background has no userManager, so it cannot refresh tokens itself — refresh remains owned by the web app, which this change defers to.
  • Optional follow-up (out of scope): when signinSilent() itself fails in the web app (refresh token revoked/expired), the add-on isn't notified. Posting SIGN_OUT on silent-refresh failure would let the menu revert to logged-out cleanly — without indiscriminately closing tabs mid-session.

Applicable Issues

Closes #948

Screenshots

N/A — behavioral fix, no UI change.

getLoginState() treated an expired OIDC access token (short-lived
`expires_at`) as logged out and called closeAllTbProTabs(), which removed
every send.tb.pro tab — including a Send dashboard tab just opened from the
accounts dashboard inside Thunderbird. The session is still valid: the Send
web app refreshes the access token transparently via signinSilent() using
the refresh_token.

Make getLoginState() a read-only probe: report logged-in based on a stored
session with a refresh_token, regardless of access-token expiry, and drop the
destructive closeAllTbProTabs()/storage-wipe/menuLogout() side effects (real
logout already flows through the SIGN_OUT path). Remove the now-unused
closeAllTbProTabs() helper. Add menu.test.ts covering the regression.

Closes #948

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aaspinwall aaspinwall requested a review from radishmouse June 30, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send dashboard tab closes when opened from accounts dashboard if add-on access token has expired

1 participant