[BUG] macOS: claude auth login reports success but CLI stays unauthenticated - hasAvailableSubscription false on an active Stripe subscription, and no credential is persisted

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

Bug Description

On macOS, claude auth login completes and prints Login successful., but the CLI remains entirely unauthenticated. claude auth status reports loggedIn: false / authMethod: "none", and any claude -p invocation fails with Failed to authenticate: OAuth session expired and could not be refreshed. ~/.claude.json shows hasAvailableSubscription: false against an active stripe_subscription.

This is not the same as #93313 or #33119, where authentication succeeds and only Remote Control is gated. Here the CLI is unusable: loggedIn never becomes true. It matches #51971 (closed, no fix, no maintainer response), including that reporter's observation that the trigger appears to be an active subscription and a Console organization on the same email address.

Reproduction, from a fully clean credential state

To rule out every client-side cause, all stored credentials were removed first:

security delete-generic-password -s "Claude Code-credentials"   # deleted
rm ~/.claude/.credentials.json                                   # absent
claude auth status  ->  loggedIn: false, authMethod: "none"

Then:

claude auth login
  Opening browser to sign in...
  Paste code here if prompted > Login successful.

claude auth status
  { "loggedIn": false, "authMethod": "none", "apiProvider": "firstParty" }

After that successful login, nothing was persisted: no Claude Code-credentials keychain item was created, and no ~/.claude/.credentials.json was written.

The OAuth exchange itself clearly succeeds -- ~/.claude.json oauthAccount is populated with the correct account UUID, email, organization UUID, organizationRole: owner, and billingType: stripe_subscription -- yet:

claudeMaxTier               = not_max
hasAvailableMaxSubscription = false
hasAvailableSubscription    = false

The requested scope set includes user:profile:

scope=org:create_api_key user:profile user:inference
      user:sessions:claude_code user:mcp_servers user:file_upload

Secondary finding: a login can write a credential with empty tokens

Before the clean-state test, an earlier login on the same machine wrote a keychain record that was structurally valid but had its secrets blanked:

{
  "claudeAiOauth": {
    "accessToken":  "",          // empty string
    "refreshToken": "",          // empty string
    "expiresAt": 0,
    "scopes": ["user:file_upload","user:inference","user:mcp_servers",
               "user:profile","user:sessions:claude_code"],
    "subscriptionType": "...",
    "rateLimitTier": "..."
  },
  "organizationUuid": "..."
}

Scopes, subscription type and organization survived; both tokens were empty and expiresAt was 0. That record fully explains the runtime error -- expiresAt: 0 reads as expired, and there is no refresh token to refresh with -- but it should not have been written in that state.

The same login path also left ~/.claude/.credentials.json malformed (truncated by one closing brace, so nothing could parse it) and dropped two mcpOAuth entries that had been present, shrinking the file from 1147 to 556 bytes. Both look like the same writer failing to persist string values.

Also observed: unbounded keychain item accumulation

The login keychain holds 89 Claude Code-credentials-<8 hex> items, accumulating at almost exactly one per day (73 of 89 share the same hour of day), spanning 2026-04-25 to present. This appears to be #91158. Mentioned only because it produced a large amount of noise while diagnosing the above; it is not the cause.

claude doctor output is misleading here

- macOS Keychain is not writable. Console login will fail to save your API key.
  Fix: Run: security unlock-keychain ~/Library/Keychains/login.keychain-db

The keychain is not the problem. It reports no-timeout (unlocked), and generic-password items can be created, updated in place and deleted successfully via /usr/bin/security on this machine -- verified with a throwaway item. The ACLs on existing Claude Code-credentials* items are also consistent with each other (entry granting decrypt lists /usr/bin/security, partition apple-tool:), so there is no ACL divergence between working and non-working entries. This warning sends people toward unlock-keychain, which cannot help, and away from the entitlement flag that is actually stuck.

Expected

claude auth login succeeding should leave the CLI authenticated, or fail with an actionable message naming the entitlement problem.

Actual

Login succeeds server-side, hasAvailableSubscription remains false, no credential is persisted, and the CLI stays unusable. No client-side remedy reaches it -- #51971's reporter additionally tried reinstalling Node and Claude Code, deleting ~/.claude.json, clearing browser cookies, deleting the Console organization, and hand-patching hasAvailableSubscription to true, all without effect.

Environment

  • Claude Code 2.1.206 (homebrew, darwin-arm64)
  • macOS, zsh
  • Subscription active, billed via Stripe, account is organizationRole: owner of a Console organization on the same email address

Account UUID, organization UUID and email are deliberately omitted from this public issue and can be supplied privately for the manual entitlement check this appears to need.

Related

  • #51971 -- same symptom, closed without fix or maintainer response
  • #93313 -- same stale flag, milder symptom (auth works, Remote Control gated)
  • #33119 -- closed, stale
  • #91158 -- keychain item accumulation

View original on GitHub ↗