跳至内容

Junyi's Lab

Claude Code 在 tmux 里要求重新登录?八成是 macOS Keychain 的锅

Table of Contents

终端里 claude 好好的,Team Account 也认得,进了 tmux 就让我重新登录。折腾了一会儿才发现是 macOS Security Session 的老问题。

# 现象

Ghostty 里直接跑 claude,没问题。tmux 里跑,要求登录。

排查过程(点击展开)

## 环境变量?

第一反应是 tmux 里环境变量不一样。

env | grep -iE 'claude|anthropic'

两边都没有。Claude Code 认证不存环境变量。

## 配置文件?

cat ~/.claude/.credentials.json 2>/dev/null || echo "no credentials file"

也没有。不在文件系统里。

## Keychain

security dump-keychain 2>&1 | grep -i -A3 'claude\|anthropic'

找到了,存在 macOS Keychain 里,service name 是 Claude Code-credentials:

0x00000007 <blob>="Claude Code-credentials"
"acct"<blob>="junyi"
"svce"<blob>="Claude Code-credentials"
keychain: "/Users/junyi/Library/Keychains/login.keychain-db"

然后试了下:

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

终端里能输出 token,tmux 里报错。问题在这。

# 为什么

macOS 的 Keychain 访问绑在 Security Session 上,底层对应的是 Bootstrap Namespace。你开终端窗口的时候,进程会挂到当前用户的 Aqua session,Keychain 就是通过这个 session 解锁的。

但 tmux server 是个常驻后台进程,第一次 tmux new 的时候启动,之后就一直活着。你后面 tmux attach 的时候,tmux server fork 出来的 shell 继承的是 server 启动时的那个旧 session,不是你当前的 Aqua session。

正常终端:
  Ghostty → fork shell → 继承 Aqua session → ✅ 能读 Keychain

tmux:
  Ghostty → attach → tmux server (旧进程)
                       → fork shell → 继承旧 session
                                       → ❌ 读不了 Keychain

pbcopy/pbpaste 在 tmux 里挂掉也是这个原因。

# 修复

装 reattach-to-user-namespace,让 tmux 里的进程重新接入当前用户的 Aqua session:

brew install reattach-to-user-namespace

~/.tmux.conf 加一行:

set-option -g default-command "reattach-to-user-namespace -l ${SHELL}"

然后杀掉整个 tmux server 重开。kill-session 没用,新 window 也没用,都还是从旧 server fork 的:

tmux kill-server
tmux new -s main

验证:

security find-generic-password -s "Claude Code-credentials" -a "$USER" -w 2>&1 | head -c 50

能输出 token 就说明通了。

# 顺带一提

tmux 里这些问题多半也是同一个原因:

  • pbcopy/pbpaste 不工作
  • ssh-agent 访问不了
  • osascript 执行失败
  • gh auth、op 等 CLI 工具认证挂了

都是 reattach-to-user-namespace 一把搞定。