fix(auth): shouldRefreshToken never refreshed a credential with no stored expiresAt (#792) - #793
Merged
developer-ainative merged 1 commit intoSep 16, 2026
Conversation
…ored expiresAt (#792) A credential row with no expiresAt at all (every row captured before the #443/#664 fix started populating it) made shouldRefreshToken(undefined) return false — treated as an eternal token, never proactively refreshed no matter how stale. Confirmed live while investigating #778: Fieldko's stored zerocrm credential was genuinely dead (core's /api/v1/auth/me returned 401 AUTH_TOKEN_INVALID) yet resolveFounderCredential happily returned it as valid because shouldRefreshToken(undefined) said no refresh was needed. A missing expiresAt means "we don't know", not "assume forever" — flip the default to assume a refresh is needed, matching the same conservative philosophy provision/route.ts already uses for its own missing-expires_in fallback. Both real call sites checked safe: auth.ts guards its call behind an expiresAt truthy check (unreachable branch there), and primitive-credentials.ts already degrades gracefully when no refresh token was ever captured either.
developer-ainative
deleted the
fix/issue-792-token-refresh-undefined-expiresat
branch
September 16, 2026 18:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
expiresAt(every row captured before the Cody's codegen prompt told generated apps to fetch() primitive APIs directly — guaranteed runtime failure #443/fix(build): founder credential capture never ran when getToken returned null #664 fix started populating it) madeshouldRefreshToken(undefined)returnfalse— treated as an eternal token, never proactively refreshed no matter how stale.zerocrmcredential was genuinely dead (core's own/api/v1/auth/mereturned401 AUTH_TOKEN_INVALID) yetresolveFounderCredential(noforceRefresh) happily returned it as valid becauseshouldRefreshToken(undefined)said no refresh was needed.expiresAtmeans "we don't know," not "assume forever" — flip the default to assume a refresh is needed, matching the same conservative philosophyprovision/route.tsalready uses for its own missing-expires_infallback.auth.tsguards its call behind anexpiresAttruthy check (the!expiresAtbranch is unreachable there), andprimitive-credentials.tsalready degrades gracefully when no refresh token was ever captured either — so worst case is identical behavior to today, best case is a stale credential actually gets refreshed instead of silently staying dead forever.Test plan
__tests__/lib/auth/tokenRefresh.test.ts(4 tests) — confirmed the core regression-guard assertion genuinely fails against the pre-fixreturn falsecode before finalizing the fixnpx tsc --noEmit— cleannpx vitest run— full suite: 5631 passed, 0 failed