VPS Notes
VPS

Claude Code のログインが切れる理由と再ログイン: 期限は約 30 日で延びない。常駐エージェントで確かめ、切れる前に Telegram で知らせる

常駐させた Claude Code がログイン切れで止まりました。期限は .credentials.json の refreshTokenExpiresAt で、約 30 日、使っても延びません。確かめ方、7 日前に Telegram で知らせる cron、再ログイン、setup-token を採らない理由まで。

claude-codeai-agentremote-controltelegramxserver-vps

本記事にはプロモーション (アフィリエイト広告) が含まれます。

「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 種類に増えるので、採りませんでした。

この記事で使う環境

XServer VPS クラウド
4GB (4 コア) で月 2,480 円〜。iris を最初に常駐させた VPS。自宅にサーバーを置けないなら、Claude Code を 24 時間動かしておく場所として使えます。
公式サイトを見る

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 つです。

月 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 (常駐させるサーバー) 向けです。

次にやること

まとめ

XServer VPS クラウド
iris を最初に常駐させた VPS。常駐するのは Claude Code 1 つなので 2GB プランでも動きます。期限の確かめ方と通知のスクリプトは、この記事のまま使えます。
公式サイトを見る