[BUG] macOS OAuth credential rotation resets Keychain ACL and invalidates Always Allow

Status Open
Reported on v2.1.280
Maintainer reply None cached
Activity 0 comments · opened Sep 23, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

On macOS, normal Claude Code OAuth credential rotation rewrites the access controls of the Claude Code-credentials login-Keychain item. This removes a signed third-party application's Team ID from the item's partition_id ACL and invalidates a macOS Always Allow grant that was working immediately before the rotation.

I captured the complete transition with CodexBar, but the problem is not CodexBar-specific: any independently signed app that the user explicitly grants access to the Claude credential loses effective access when Claude rewrites the item.

Before rotation:

  • The decrypt ACL listed /Applications/CodexBar.app with a valid Developer ID requirement.
  • The partition_id ACL contained apple-tool:, teamid:Y5PE65HELJ.
  • CodexBar read the item silently with status=0 in approximately 3 ms.

After normal Claude Code use refreshed the credential:

  • The item's modification time changed to 2026-09-23T04:54:12Z.
  • The legacy decrypt ACL still listed /Applications/CodexBar.app (OK).
  • The partition_id ACL had been reset to only apple-tool:; teamid:Y5PE65HELJ was gone.
  • The next direct read caused macOS to request the login-Keychain password again, despite the earlier Always Allow choice.

Re-adding the Team ID repairs access only until the next Claude credential rotation, when it is removed again.

What Should Happen?

Updating the OAuth credential value should preserve the existing Keychain item's user-configured ACL and partition list.

The preferred implementation would update only kSecValueData on the existing exact item using SecItemUpdate (or an equivalent value-only update) without supplying a replacement kSecAttrAccess. If replacement is genuinely required, Claude Code should copy and reapply the existing access controls rather than resetting them to the writer's defaults.

A user's macOS Always Allow decision should remain effective across routine token refreshes.

Error Messages/Logs

# Before Claude credential rotation
applications (2):
    /usr/bin/security (OK)
    /Applications/CodexBar.app (OK)
partition_id description: apple-tool:, teamid:Y5PE65HELJ

Claude keychain data read result ... status=0

# After Claude credential rotation
"mdat" = "20260923045412Z"
applications (2):
    /usr/bin/security (OK)
    /Applications/CodexBar.app (OK)
partition_id description: apple-tool:

The credential value and all account-identifying data are intentionally omitted.

Steps to Reproduce

  1. On macOS, sign in to Claude Code with a Claude subscription so Claude Code-credentials exists in the login Keychain.
  2. From another stable, signed application, read that item and choose macOS Always Allow.
  3. Confirm subsequent reads are silent.
  4. Run security dump-keychain -a ~/Library/Keychains/login.keychain-db and verify the reader appears in the decrypt ACL and its teamid: appears in the partition list. Do not use -d; no credential data is needed.
  5. Continue normal Claude Code usage until its OAuth credential refreshes.
  6. Dump the ACL again. The credential modification time has advanced, but the reader's teamid: partition has disappeared and only apple-tool: remains.
  7. Read from the previously authorized application again. macOS asks for the login-Keychain password despite the prior Always Allow grant.

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

Unknown

Claude Code Version

2.1.280 (Claude Code)

Platform

Anthropic API

Operating System

macOS 26.4.1 (25E253), arm64

Terminal/Shell

Other (Ghostty / zsh)

Additional Information

No passwords, OAuth tokens, account emails, raw credential payloads, or decrypted Keychain data are included.

View original on GitHub ↗