Summary
When multiple cx processes use the same OAuth profile concurrently at the point where the access token needs refreshing, token refresh and OS-keyring persistence appear to race.
One process succeeds, while sibling processes may report either invalid_grant or a Keychain duplicate-item error. A subsequent serialized cx command succeeds without reauthentication, so the profile is not actually unauthenticated.
Environment
cx 0.1.16
- macOS
- OAuth profile with tokens stored in the OS keyring
- Observed with read-only telemetry commands using the same profile
Reproduction
- Configure an OAuth profile using OS-keyring storage.
- Reach a state where the access token needs refreshing while the refresh token is valid.
- Launch several authenticated commands concurrently against the same profile, for example:
for n in 1 2 3 4; do
cx logs 'source logs' --start now-5m --limit 1 --read-only --output agents \
> "/tmp/cx-$n.out" 2>&1 &
done
wait
This is especially easy to trigger in agent workflows that perform telemetry discovery in parallel.
Actual behavior
Some commands fail with:
Configuration error: OAuth token refresh failed for profile '<profile>'.
...
Token refresh failed (400 Bad Request):
{"error":"invalid_grant","error_description":"The provided authorization grant is invalid."}
Another concurrent process may fail with:
Configuration error: Failed to store secrets in keyring
...
Platform secure storage failure: The specified item already exists in the keychain.
At least one concurrent command can still succeed. Running another authenticated command serially afterward also succeeds without running cx profiles add, showing that one process stored a valid refreshed token.
Expected behavior
Concurrent commands sharing an OAuth profile should coordinate refresh so that:
- only one process exchanges the refresh token;
- waiting processes reread the newly stored tokens after the refresh completes;
- keyring persistence does not fail on an existing item;
- all commands proceed with the valid access token.
Likely cause
If the OAuth provider rotates refresh tokens, multiple processes can read the same refresh token before any process stores its replacement. The first exchange succeeds and invalidates the old grant; later exchanges receive invalid_grant. Concurrent Keychain writes can independently collide.
Suggested direction
Use a cross-process lock keyed by profile around refresh and token persistence. After acquiring the lock, reread the profile/keyring state because another process may already have refreshed it. Updating/replacing keyring entries atomically—and optionally retrying once after rereading on invalid_grant—would make parallel CLI use reliable.
Impact
This produces intermittent false “reauthenticate” guidance in parallel automation and agent sessions, even though credentials remain valid. Serial use usually appears healthy, which makes the failure confusing and hard to diagnose.
Summary
When multiple
cxprocesses use the same OAuth profile concurrently at the point where the access token needs refreshing, token refresh and OS-keyring persistence appear to race.One process succeeds, while sibling processes may report either
invalid_grantor a Keychain duplicate-item error. A subsequent serializedcxcommand succeeds without reauthentication, so the profile is not actually unauthenticated.Environment
cx 0.1.16Reproduction
This is especially easy to trigger in agent workflows that perform telemetry discovery in parallel.
Actual behavior
Some commands fail with:
Another concurrent process may fail with:
At least one concurrent command can still succeed. Running another authenticated command serially afterward also succeeds without running
cx profiles add, showing that one process stored a valid refreshed token.Expected behavior
Concurrent commands sharing an OAuth profile should coordinate refresh so that:
Likely cause
If the OAuth provider rotates refresh tokens, multiple processes can read the same refresh token before any process stores its replacement. The first exchange succeeds and invalidates the old grant; later exchanges receive
invalid_grant. Concurrent Keychain writes can independently collide.Suggested direction
Use a cross-process lock keyed by profile around refresh and token persistence. After acquiring the lock, reread the profile/keyring state because another process may already have refreshed it. Updating/replacing keyring entries atomically—and optionally retrying once after rereading on
invalid_grant—would make parallel CLI use reliable.Impact
This produces intermittent false “reauthenticate” guidance in parallel automation and agent sessions, even though credentials remain valid. Serial use usually appears healthy, which makes the failure confusing and hard to diagnose.