Repository navigation
fix(auth): stop parallel commands from logging the user out - #674
Closed
amitbardos wants to merge 1 commit into
Closed
amitbardos wants to merge 1 commit into
amitbardos wants to merge 1 commit into
Conversation
Refresh tokens rotate on use. When several CLI processes found an expired token at once, each refreshed with the same refresh token; every refresh after the first was rejected and its catch deleted ~/.base44/auth for all of them. The in-memory refreshPromise only guarded a single process. Hold a lock file across processes while refreshing, and use the token another process already wrote instead of refreshing again. Delete auth only when the server rejects the refresh token, not on network or server errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/cli@0.2.2-pr.674.03ac2f7Prefer not to change any import paths? Install using npm alias so your code still imports npm i "base44@npm:@base44-preview/cli@0.2.2-pr.674.03ac2f7"Or add it to your {
"dependencies": {
"base44": "npm:@base44-preview/cli@0.2.2-pr.674.03ac2f7"
}
}
Preview published to npm registry — try new features instantly! |
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.
Note
Description
Running multiple Base44 CLI commands in parallel (common when agents drive the CLI) could log the user out entirely. Refresh tokens rotate on use, so when several processes each found an expired access token, they all refreshed with the same refresh token — every refresh after the first was rejected, and the blanket
catchinrefreshAndSaveTokens()deleted~/.base44/auth/for all of them. This PR adds a cross-process lock file around the refresh and narrows auth deletion to the one case that actually means "log in again".Related Issue
None
Type of Change
Changes Made
withRefreshLock()incore/auth/config.ts: acquires~/.base44/auth/auth.json.lockwithopen(path, "wx"), retrying every 50ms, and reclaims a lock whose mtime is older than 30s (left by a process that died mid-refresh). The lock is always released in afinally.refreshAndSaveTokens()now snapshots the refresh token before taking the lock and re-readsauth.jsonafter acquiring it. If the refresh token changed, another process already refreshed, so it returns that process's access token instead of burning the rotated token.ApiErrorwith status 400 or 401). Network failures and 5xx responses now returnnulland leave the credentials on disk.refreshPromiseguard is kept and its comment clarified — it only dedupes within a single process; the lock file covers the cross-process case.docs/api-patterns.mdto document the lock file, the re-read-after-lock behavior, and the narrowed deletion rule (including the env-seeded auth section, which referenced the old "refresh fails to delete" wording).Testing
npm test)New test in
packages/cli/tests/cli/authorization.spec.ts: twoagents pushprocesses run concurrently against a mock/oauth/tokenroute that honors the refresh token exactly once and then returns400 invalid_grant. The first refresh is held until the second process arrives (or 2s elapse), forcing the race. Both commands must succeed andauth.jsonmust end up holding the rotated refresh token. Per the author, this fails 3/3 onmainand passes 10/10 with the fix.Checklist
docs/(AGENTS.md) if I made architectural changesAdditional Notes
The lock is advisory and file-based, so it works across independent
npx base44processes on the same machine without any new dependency. Stale-lock reclamation is time-based (30s), which is the usual trade-off: a refresh that legitimately takes longer than 30s could have its lock stolen, degrading to the pre-existing behavior rather than making anything worse.The full suite was not run in this review environment (test execution was not permitted here), so the "all tests pass" box is left unchecked pending CI.
🤖 Generated by Claude | 2026-10-22 12:55 UTC | c653912