anthropics / anthropics/claude-code

macOS: token refresh rewrites Claude Code-credentials in place and drops its keychain ACL, restarting the password prompt loop

Đang mở
#94,491 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:auth bug has repro platform:macos
Ngôn ngữ chính
Python
Star
145k
Fork
23.1k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

## Summary

On macOS, every OAuth token refresh rewrites the `Claude Code-credentials` keychain item **in place** and drops the item's ACL in the process. Any grant the user has given — via "Always Allow", or via a manual `security set-generic-password-partition-list` repair — is wiped, and the "security wants to access key 'Claude Code-credentials'" password prompt loop starts over roughly every few hours.

This is the same user-visible symptom as #89985, which covers why the prompt appears at all (credentials are read by forking `/usr/bin/security`, so `securityd` evaluates the ACL against a generic Apple tool). This issue is narrower: it isolates the **write** path as an independently fixable cause, with evidence that the item is updated rather than replaced.

## Environment

- macOS 26.6.2 (25G83), Apple Silicon
- Claude Code 2.1.270 (bundled in Claude.app) and 2.1.271 (standalone CLI)
- Keychain item: service `Claude Code-credentials`, login keychain (`no-timeout`, unlocked)

## Evidence: the item is modified in place, not recreated

Across a token refresh, `cdat` is unchanged while `mdat` moves:

```
cdat = 20260908181554Z (unchanged across the refresh)
mdat = 20260915031337Z -> 20260915110920Z
```

A delete + re-add would produce a new `cdat`. So the write path reaches the existing item and drops its ACL along the way, rather than replacing the item wholesale. That suggests the fix may be small: preserve the existing `SecAccess` on update instead of writing a default one.

## Reproduction

1. Repair the grant on the item:

```
security set-generic-password-partition-list -S 'apple:,apple-tool:,teamid:XDX9UJP7V4' \
-s "Claude Code-credentials" -a ~/Library/Keychains/login.keychain-db
```

2. Confirm it worked — a scripted read returns the secret with no dialog:

```
security find-generic-password -s "Claude Code-credentials" -a -w
```

3. Wait for a token refresh (`mdat` on the item advances).
4. Run the same read again. It now blocks on a password dialog.

In step 4 the test process died by `SIGALRM` (exit 142) with nothing on stderr — the dialog was open and waiting, not an error return.

## Control

This account had a second credential item from another install (`Claude Code-credentials-`). Both items were repaired at the same moment. The second one has not been written since, and still reads silently; only the item that got rewritten regressed.

Same machine, same repair, same keychain state — the only difference is that one was rewritten. That isolates the regression to the write path.

## Contributing factor: multiple credential items

Installs using different config dirs create separate `Claude Code-credentials-` items, each with its own ACL, so a grant given for one does nothing for the others. This account had three, one of them stale from an install that no longer existed. Combined with concurrent Claude Code processes each forking their own `security` (see #89985), a single expired grant produces ~10 simultaneous dialogs.

## Expected

A token refresh should preserve the item's existing ACL, so that a grant the user has given survives until they revoke it.

## Notes

There appears to be no supported way to opt out of the keychain on macOS — the binary only exposes `--use-mock-keychain` (test) and an internal `allowUnrestrictedAccess` for CI, neither configurable by users. Happy to capture `securityd` logs around a refresh if useful.

— samirhvbr

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.