同一マシンで 2つの Claude Code アカウントを使い分けていたときのことです。UI が「active」として強調しているアカウントと、実際に claude が使っているアカウントが食い違っていました。
原因は Claude Code の認証が2層構造になっていて、それぞれが独立して動くからです。
この記事では、その仕組みと、setup-token の取得・設定、乖離したときの修復手順を説明します。
2層構造の概要
Claude Code の認証は以下の 2つのレイヤーで構成されています。
| レイヤー | 実体 | 優先度 |
|---|---|---|
| Layer 1 (login) | ~/.claude/.credentials.json |
フォールバック |
| Layer 2 (token pin) | 環境変数 CLAUDE_CODE_OAUTH_TOKEN
|
常に優先 |
ランタイムのチェックロジックはシンプルです。
if $CLAUDE_CODE_OAUTH_TOKEN が環境にある:
→ そのトークンで実行
else:
→ ~/.claude/.credentials.json を使う
環境変数が常に勝ちます。
claude login でブラウザ認証し直しても、CLAUDE_CODE_OAUTH_TOKEN がセットされていれば無視されます。UIのhighlight(login状態)と実際の実行アカウント(token pin)がずれる原因はここにあります。
setup-token とは何か
CLAUDE_CODE_OAUTH_TOKEN にセットするトークンとして、claude setup-token が発行する長期クレデンシャルがあります。
通常の OAuth ログインとの違いは1点だけです。ここが核心です。
| OAuth (credentials.json) | setup-token | |
|---|---|---|
| リフレッシュ | 自動(refresh token あり) | なし(期限切れ→再発行) |
| 有効期限 | 短命・自動更新 | 1年固定 |
| ブラウザ | 必要(初回) | 不要 |
| 複数マシン共有 | 各マシンで個別ログインが必要 | 同一トークンを共有可 |
CI 環境・リモートマシン・ヘッドレスサーバーで Claude Code を使う場合、setup-token が向いています。ブラウザが使えない場所での唯一の選択肢です。複数マシンへの配布も、同じトークン文字列を secrets マネージャー経由で配るだけで済みます。1台1台ブラウザでログインする必要がありません。
setup-token の取得手順
対象アカウントで Claude Code にログインした状態で実行します。
claude setup-token
成功すると sk-ant-oat01-... 形式の長い文字列が表示されます。この文字列は一度しか表示されません。 安全な場所に保存してください。
# 環境変数にセット(セッション内のみ有効)
export CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-..."
# シェル起動時に自動設定する場合(~/.bashrc や ~/.zshrc に追記)
echo 'export CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-..."' >> ~/.bashrc
CLAUDE_CODE_OAUTH_TOKEN をセットした状態で claude を起動すると、Layer 1(credentials.json)の内容に関係なく、そのトークンのアカウントで動きます。
split 運用:login と token pin を別アカウントにする
2層構造を意図的に使うパターンがあります。
- Layer 1(login): Max アカウント(高レートリミット、インタラクティブ作業用)
- Layer 2(token pin): サブアカウント(自動化ジョブ・CI 用)
この構成では、claude コマンドの実際の実行はサブアカウントで動きながら、UI の login 表示は Max アカウントになります。ツールが明示的に両方を確認しない限り、見た目と実態がずれます。
意図してこの構成を使う場合は、どちらのレイヤーが「今のactive」かを常に意識してください。把握していないと、意図しないアカウントで課金が積まれます。
sync_broken の診断と修復
症状のうち3つ全部に当てはまったので、最初はバグだと思って1時間調査しました。
2層が乖離した状態を「sync_broken」と呼びます。典型的な症状は以下の通りです。
- UI のアクティブ強調が直感と合わない
- 使用量カウンターが期待したアカウントに積まれない
- アカウントを切り替えたはずなのに挙動が変わらない
診断手順:
# Layer 1 の確認(どのアカウントが login 済みか)
cat ~/.claude/.credentials.json | python3 -c "
import json, sys
d = json.load(sys.stdin)
# oauthAccount に email や uuid が入っている
print(d.get('oauthAccount', {}))
"
# Layer 2 の確認(token pin がセットされているか)
echo "CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN:0:20}..."
修復は「どちらを使いたいか」を決めてから:
# token pin を使いたい場合 → Layer 1 のズレを気にしない
# Layer 1 を使いたい場合 → token pin を解除する
unset CLAUDE_CODE_OAUTH_TOKEN
# シェル起動スクリプトに書いてある場合は該当行を削除してから
# 新しいターミナルで確認
claude-shift で 2層を管理する
手動管理が面倒な場合は、複数アカウント管理ツール claude-shift が 2層の切り替えを UI で管理できます。
-
login 切替ボタン:
credentials.jsonを差し替えて Layer 1 を切り替え -
token 切替ボタン:
CLAUDE_CODE_OAUTH_TOKENを差し替えて Layer 2 を切り替え - アクティブ強調モード設定: 「実効優先」「login」「両方」から選択し、どちらの状態を青いカードで強調するかを制御
split 状態(login ≠ token pin)はグローバルバナーで警告表示されます。
実践上の注意点 3つ
-
CLAUDE_CODE_OAUTH_TOKENはclaude loginより強い。 ログインし直しても token pin はクリアされません。 -
setup-token は自動ローテーションしません。 1年後に期限切れになります。カレンダーにリマインダーを設定しておくことを推奨します。
-
同一アカウントで setup-token を複数発行できます。 マシンごとに別トークンを発行して管理するとローテーション時の影響範囲を絞れます。
📘 Claude Code の設計・運用をさらに詳しく知りたい方へ
実践Claude Code — CLAUDE.md設計からコンテキスト管理まで体系的に解説
まとめ
Claude Code の認証は、多くのユーザーが知っている credentials.json(Layer 1)と、実行時に優先される CLAUDE_CODE_OAUTH_TOKEN(Layer 2)の2層構造です。
setup-token はこの Layer 2 向けの長期クレデンシャルで、CI・マルチマシン構成で特に有効です。
2層が乖離したときは、どちらを使いたいかを決めてから、不要な方を解除するだけで解消できます。知ってさえいれば、5分かかりません。
なぜこの2層設計になっているのか、setup-token が refresh token を持たない設計の意図については、こちらの記事で詳しく扱っています。
