Claude Code のログインが切れる理由と再ログイン: 期限は約 30 日で延びない。常駐エージェントで確かめ、切れる前に Telegram で知らせる
常駐させた Claude Code がログイン切れで止まりました。期限は .credentials.json の refreshTokenExpiresAt で、約 30 日、使っても延びません。確かめ方、7 日前に Telegram で知らせる cron、再ログイン、setup-token を採らない理由まで。
本記事にはプロモーション (アフィリエイト広告) が含まれます。
「Claude Code のログインが急に切れた」「毎回ログインし直すのが面倒」で調べている人向けに、先に結論を置きます。
Claude Code のログインは、再ログインから約 30 日で切れます。毎日使っていても延びません。 期限は Linux なら ~/.claude/.credentials.json の refreshTokenExpiresAt に書いてあります。手元で使うだけなら、切れたときに /login し直せば済みます。困るのは、Claude Code を常駐させて無人で動かしている場合です。誰も画面を見ていないので、切れたことに気づくのが遅れます。
私は自宅のサーバーで Claude Code のエージェント「iris」を常駐させています。10 月 24 日の朝、毎週土曜の振り返りの仕事が OAuth session expired で止まりました。この記事では、そこから調べて分かった期限の仕組みと、切れる 7 日前の金曜に Telegram で知らせる cron を紹介します。長期トークン (claude setup-token) も試しました。cron の仕事には使えるものの、常駐の Remote Control には使えません。管理する期限が 2 種類に増えるので、採りませんでした。
この記事で使う環境
- Claude Code 2.1.283。契約は Claude Pro
- 常駐エージェント iris:
claude remote-controlを tmux で動かし、スマホの Claude アプリから話しかける。毎週土曜 5:00 に cron のclaude -pが 1 週間のメモを振り返る (週次レビュー)。作り方は VPS に Claude Code のエージェントを常駐させる記事 - iris は XServer VPS クラウド (Ubuntu 24.04) で作り、9 月 26 日に自宅のラズパイ (Raspberry Pi 5、Ubuntu 24.04) へ移した。この記事の実測はラズパイでの値。期限の仕組みは Linux なら VPS でも同じ
- 通知は Telegram の Bot
10 月 24 日の朝、週次レビューが止まった
iris の週次レビューは、土曜 5:00 に cron から claude -p を呼ぶだけのスクリプトです。出力はログファイルに追記しています。10 月 24 日のログの最後は、この 1 行でした。
Failed to authenticate: OAuth session expired and could not be refreshed
いつもなら 5 時台に Telegram へ届く「今週の記事候補」が、この日は届きませんでした。
私が気づいたのは、ログを見たからではありません。その朝はゴルフの予定があり、ゴルフ場の場所と移動時間を iris に調べてもらおうとしました。スマホのアプリで話しかけても、反応がありません。出発前の朝一だったので、慌ててラズパイに入って再ログインしました (05:15)。
常駐の Remote Control も同じログインを使っています。ログインが切れると、こちらも止まります。公式ドキュメントにも、Remote Control のセッションがログインの期限を越えると進まなくなり、サインインし直すまで回復しない、とあります (Authentication、2026-10-25 確認)。
ログインの期限はどこにあるか
Linux では、ログイン情報は ~/.claude/.credentials.json に保存されます (権限 600)。macOS は Keychain に入るので、このファイルはありません。中身はこういう形です (トークンは伏せています)。
{
"claudeAiOauth": {
"accessToken": "sk-ant-oat01-...",
"refreshToken": "sk-ant-ort01-...",
"expiresAt": 1792905398525,
"refreshTokenExpiresAt": 1794626989525,
"scopes": ["user:file_upload", "user:inference", "user:mcp_servers", "user:plugins", "user:profile", "user:sessions:claude_code"],
"subscriptionType": "pro",
"rateLimitTier": "default_claude_ai"
}
}
期限は 2 つあります。
| 項目 | 長さ | 切れたら |
|---|---|---|
expiresAt (アクセストークン) |
8 時間 | Claude Code が refreshToken で自動的に取り直す。何もしなくてよい |
refreshTokenExpiresAt (リフレッシュトークン) |
約 30 日 | 自動では取り直せない。/login し直すまで動かない |
止まる原因になるのは後者です。トークンそのものを画面に出さずに、期限だけを見るにはこうします。
python3 -c "
import json, datetime
v = json.load(open('$HOME/.claude/.credentials.json'))['claudeAiOauth']
for k in ('expiresAt', 'refreshTokenExpiresAt'):
print(k, datetime.datetime.fromtimestamp(v[k] / 1000))
"
iris で実行した結果です。
expiresAt 2026-10-25 13:16:38.525000
refreshTokenExpiresAt 2026-11-22 08:29:49.525000
手元で Claude Code を起動している人には、期限の 3 日前から起動時に Your login expires in 3 days · run /login to renew という警告が出ます (公式ドキュメント)。常駐の Remote Control や cron の claude -p では、この警告を見る人がいません。
期限は延びるか: 確かめた
「毎日使っていれば延びるのでは」と思って確かめました。延びません。
iris は 10 月 24 日 05:15 に再ログインしました (~/.claude/history.jsonl に /login の記録があります)。そのときの refreshTokenExpiresAt は 11 月 22 日 08:29 でした。再ログインから 29 日と 3 時間 13 分 です。
その後もアクセストークンは 8 時間ごとに自動で更新されています。翌朝 05:16 に .credentials.json が書き換わったあとも、refreshTokenExpiresAt は 11 月 22 日 08:29 のままでした。使い続けても、期限は再ログインした時点で決まります。
前回の分も振り返りました。history.jsonl を見ると、ラズパイで最初にログインしたのは 9 月 26 日 13:04 です。10 月 23 日 06:02 までは iris が動いて作業メモを commit しています。10 月 24 日 05:00 の週次レビューは失敗しました。前回は 28 日弱 で切れていたことになります。今回の 29 日と 3 時間より短いので、期限の長さは毎回同じとは限りません。余裕を見て、7 日前に知らせることにしました。
切れる前の金曜に Telegram で知らせる
refreshTokenExpiresAt を読んで、7 日以内に切れるなら Telegram に送るスクリプトです。毎週金曜の夜に cron で動かします。7 日の幅があるので、切れる前の最後の金曜に 1 回だけ届きます。ほかの週は何も送りません。
#!/bin/bash
# 金曜の夜に実行する。Claude のログイン (リフレッシュトークン) が 7 日以内に切れるなら Telegram で知らせる。
# 切れる前の最後の金曜に 1 回だけ届く。それ以外の週は何も送らない。
set -eu
MSG=$(python3 - <<'PY'
import json, time, datetime
v = json.load(open('/home/iris/.claude/.credentials.json'))['claudeAiOauth']
exp = v.get('refreshTokenExpiresAt')
if exp:
left = exp / 1000 - time.time()
if left < 7 * 86400:
d = datetime.datetime.fromtimestamp(exp / 1000).strftime('%m/%d %H:%M')
if left <= 0:
print(f'iris: Claude のログインが切れています ({d})。再ログインしてください')
else:
print(f'iris: Claude のログインが {d} に切れます。週末の前に再ログインしてください')
PY
)
[ -n "$MSG" ] && "$HOME/iris/bin/notify-telegram" "$MSG"
exit 0
bin/login-expiry-check という名前で保存し、chmod +x しておきます。パスの /home/iris は自分のホームに読み替えてください。notify-telegram は、Bot のトークンと chat_id を .env から読んで Telegram の API に送るだけの短いスクリプトです。作り方は iris の記事の「Telegram に通知する」 に書きました。
cron はこうです (crontab -e)。
0 21 * * 5 /home/iris/iris/bin/login-expiry-check
金曜 21:00 にしたのは、寝る前に再ログインを済ませておくためです。最初は「切れる前の土曜の朝」にしていました。ところが、私は土曜の朝にゴルフが入ることが多く、今回の期限の前日 (11 月 21 日の土曜) もそうです。今回止まったのも、まさにゴルフに出る前の朝でした。土曜の朝に通知が来ても、対応する時間がありません。iris に頼んで、前の晩の金曜 21:00 に変えました。
通知の文面は、期限を偽の値に書き換えたコピーで空打ちして確かめました。今回の期限なら、11 月 20 日 (金) 21:00 に「iris: Claude のログインが 11/22 08:29 に切れます。週末の前に再ログインしてください」と届くはずです。届いたら、この記事に画面を足します。
切れたら (切れる前に): 再ログインの手順
再ログインは、サーバーに ssh で入って Claude Code を起動し、/login を打つだけです。
ssh iris@<サーバー>
cd ~/iris
claude
Claude Code の画面で /login を打つと、ログイン用の URL が出ます。ssh 越しなのでブラウザは開きません。URL を手元のブラウザで開いて承認すると、コードが表示されます。そのコードを Paste code here if prompted の欄に貼れば Login successful と出ます。/exit で抜けて完了です。
期限は再ログインした時点から数え直しになります。切れる前に済ませても損はありません。通知が来た週の都合のよい日にやれば十分です。
常駐の Remote Control は、再ログインすれば立て直さなくても戻りました。iris の tmux の画面には、再ログインの直後に Session failed: Process exited with error と 1 行出ています。その後は自分で Connected に戻りました。アプリで「おはよう」と送ると、普通に返事が来ました。反応がなかった間に送ったゴルフ場の質問も拾って、まとめて答えてくれました。
setup-token は使えるか: 確かめて、採らなかった
「ログイン 切れる」で調べると、claude setup-token という方法が出てきます。ブラウザで承認すると、1 年有効の長期トークンが発行されます。これを環境変数 CLAUDE_CODE_OAUTH_TOKEN に入れて使います (Generate a long-lived token)。
iris で実際に発行して、3 つ確かめました。既存のログインに影響しないように、空の設定ディレクトリ (CLAUDE_CONFIG_DIR) を作って試しています。
まず、ログイン情報のない空の設定で claude -p を呼ぶと、当然こう断られます。
Not logged in · Please run /login
次に、同じ空の設定で、トークンを環境変数で渡しました。
CLAUDE_CONFIG_DIR=$(mktemp -d) CLAUDE_CODE_OAUTH_TOKEN=$(cat ~/token-file) claude -p "OK とだけ返して"
今度は OK と返ってきました。claude auth status の認証方式は "authMethod": "oauth_token" です。cron の claude -p は、長期トークンで動きます。
最後に、同じトークンで Remote Control を起動しました。
Error: Remote Control requires a full-scope login token. Long-lived tokens (from `claude setup-token` or CLAUDE_CODE_OAUTH_TOKEN) are limited to inference-only for security reasons. Run `claude auth login` to use Remote Control.
Remote Control には使えません。 長期トークンは推論 (モデルへのリクエスト) だけの権限で、Remote Control や claude.ai のコネクタ (Gmail など) には使えません。公式ドキュメントにも同じことが書いてあります。
一度は、週次レビューの claude -p だけを長期トークンで動かす形に変えました。これなら、ログインが切れても週次レビューは止まりません。しかし結局、元に戻しました。理由は 2 つです。
- 常駐の Remote Control は、どのみち約 30 日ごとの再ログインが要る
- 長期トークンも 1 年で切れる。期限を 2 種類管理することになる
月 1 回の再ログインを通知で忘れないようにすれば、常駐も週次レビューも両方動きます。仕組みが 1 つで済む方が分かりやすい、という判断です。
CLAUDE_CODE_OAUTH_TOKEN は、/login のログインより優先されます (公式ドキュメントの「Authentication precedence」)。シェルの設定ファイルや .env に書いて常駐のプロセスにまで渡ると、Remote Control が推論専用のトークンで起動して、上のエラーで止まります。使うなら、cron のコマンドにだけ渡してください。
つまずいた点
前回のログインは、思ったより早く切れていた。 iris は「約 30 日周期」と覚えていました。ところが前回は 28 日弱で切れています。「30 日目の前日に通知」のようにぎりぎりで組むと、間に合わないことがあります。7 日の余裕はそのためです。
期限が来ても、エラーは週次レビューのログにしか出なかった。 cron の出力をログファイルに追記するだけだったので、失敗しても誰にも知らせが来ません。実際に気づいたのは、出かける前に iris を頼ろうとして返事がなかったときです。いちばん使いたいときに止まっていたことになります。切れる前に知らせる通知は、この反省から足しました。
通知の曜日を一度変えた。 最初は土曜の朝にしていました。土曜の朝はゴルフで出かけることが多いので、金曜の寝る前の方が確実に対応できます。通知は、受け取ったときに動ける時間に置くのが大事です。
macOS では .credentials.json がない。 Mac の Claude Code は、ログイン情報を Keychain に保存します。この記事のスクリプトは Linux (常駐させるサーバー) 向けです。
次にやること
- 常駐エージェントそのものの作り方は VPS に Claude Code のエージェントを常駐させる記事
- 外から Claude Code を操作する Remote Control の使い方は VPS の Claude Code をスマホから操作する記事
- 常駐させたときの使用量の実績は Claude Code の料金と使用量の記事
まとめ
- Claude Code のログインは、再ログインから約 30 日で切れる (今回は 29 日と 3 時間、前回は 28 日弱)。アクセストークンは 8 時間ごとに自動更新されるが、期限そのものは延びない
- 期限は Linux なら
~/.claude/.credentials.jsonのrefreshTokenExpiresAt - 常駐させるなら、7 日前の金曜に Telegram で知らせる cron を置き、都合のよい日に
/loginし直す claude setup-tokenの長期トークン (1 年) は cron のclaude -pには使える。Remote Control には使えない。期限を 1 種類にしたいので、私は採らなかった