マキモノ
Web開発無料✅ 公式検証済みv1.0.0 / 更新

ローテーションするOAuth2リフレッシュトークンをDB永続化して壊れないようにする型

freee/Google等でリフレッシュトークンがローテーションし env固定だと初回更新後に必ず壊れる問題を、トークンをDBに持ち更新のたび書き戻す型で解決。マスタID取得・冪等ガード・段階導入まで含む会計API連携の定石。

出品者: kim@orgiast.jp1 DL📖 読込 約1,949トークン (約3円)💰 コスパ 4
トークン節約メーター83%節約
ゼロからAIに作らせた場合9,000トークン
このMDを読ませた場合1,500トークン

7,500トークンの節約 (API料金換算で約11円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。

この巻物について

ローテーションするOAuth2リフレッシュトークンをDB永続化して壊れないようにする型」は、Web開発カテゴリのAI指示書(MDファイル)です。freee/Google等でリフレッシュトークンがローテーションし env固定だと初回更新後に必ず壊れる問題を、トークンをDBに持ち更新のたび書き戻す型で解決。マスタID取得・冪等ガード・段階導入まで含む会計API連携の定石。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約7,500トークン(API料金換算で約11円)・83%のトークンを節約できます。

カテゴリ
Web開発
対応AI
claude-code、cursor、codex-cli
ライセンス
商用利用可 (再販不可)
価格
無料
ゼロから開発時
約9,000トークン
この巻物使用時
約1,500トークン
節約量
約7,500トークン (約11円)
更新日
2026-08-20

使い方 (AIに渡す3つの方法)

いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。

⬇ .md をダウンロード
claude "https://makimono-md.vercel.app/api/v1/files/oauth2-db/raw を読み込んで、この指示書どおりに実装して"
claude-codecursorcodex-cliライセンス: 商用利用可 (再販不可)

中身

ローテーションする OAuth2 リフレッシュトークンを DB 永続化して壊れないようにする型

freee・Google 等の OAuth2 API 連携で「最初は動くのに数時間〜翌日に必ず認証エラーになる」典型バグの回避策。Web アプリ(Next.js/Node 等)に外部会計・SaaS API を繋ぐときの定石。

前提となる落とし穴

多くの OAuth2 プロバイダ(freee 等)は リフレッシュトークンがローテーションする=アクセストークンを更新するたびに新しいリフレッシュトークンが発行され、古いリフレッシュトークンは即失効する。

  • リフレッシュトークンを環境変数(REFRESH_TOKEN=...)に固定で置くと、1回目の更新後に env の値が無効化され、次回のトークン更新が invalid_grant で失敗する。
  • サーバレス(複数インスタンス)では特に、どのインスタンスが更新しても env は書き換わらないので確実に壊れる。
  • 症状:「前に渡したトークンが失効していた」「初日は動いたが翌朝から連携エラー」。

解決の型:トークンを DB に持ち、更新のたびに書き戻す

  1. トークン保管テーブルを作る(単一行)。client_id / client_secret / refresh_token / access_token / access_expires_at を保持。client_id/secret も同居させると、この API 用の環境変数依存をゼロにできる(秘匿値を env に置けない/CI classifier に止められる環境で有効)。
create table oauth_tokens (
  id text primary key,           -- 'default'
  client_id text not null,
  client_secret text not null,
  refresh_token text not null,
  access_token text,
  access_expires_at timestamptz,
  updated_at timestamptz not null default now()
);
  1. getValidAccessToken() を1本用意:期限内ならキャッシュを返す。期限切れならリフレッシュし、返ってきた新 refresh_token を必ず DB に書き戻す
export async function getValidAccessToken(): Promise<string> {
  const row = await loadTokenRow();               // DB から1行
  if (row.accessToken && row.accessExpiresAt.getTime() > Date.now() + 120_000) {
    return row.accessToken;                        // まだ有効
  }
  const res = await fetch(TOKEN_URL, {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: row.clientId,
      client_secret: row.clientSecret,
      refresh_token: row.refreshToken,
    }),
  });
  if (!res.ok) throw new Error(`token refresh failed (要再認証): ${res.status}`);
  const j = await res.json();                      // { access_token, refresh_token, expires_in }
  await saveTokenRow({                             // ★ 新 refresh_token を必ず永続化
    refreshToken: j.refresh_token,
    accessToken: j.access_token,
    accessExpiresAt: new Date(Date.now() + j.expires_in * 1000),
  });
  return j.access_token;
}
  1. HTTP アダプタはトークンを受け取るだけにする(トークン管理を混ぜない)。レイヤ規約(adapters は DB/サービスを import しない)とも整合する。
export async function apiFetch<T>(path, init, accessToken): Promise<T> { /* Bearer 付与のみ */ }

初回接続(トークンの種を入れる)

  • リフレッシュトークンは 一度だけ OAuth 認可フローで取得する(これは人手が要る正規の1操作)。 authorize URL(redirect_uri=urn:ietf:wg:oauth:2.0:oob にすると画面にコードが出る CLI 向け)を開く→ログイン&許可→表示された 認可コード を1回受領→grant_type=authorization_code でトークン交換→DB にシード。
  • 以後はローテーションを DB が吸収するので、再認可は原則不要(リフレッシュトークン自体の有効期限切れ時のみ再実行)。

実装前に必ずやること:マスタ ID を「取得」する(推測しない)

会計 API 等は勘定科目・税区分・品目などを ID/コードで指定する。名前からの推測は事故る。

  • 勘定科目:GET /account_items を叩き、運用担当(経理)に「この処理はどの科目か」を実在する科目名の一覧から選んでもらう。担当が言う名前(例「仕入・原価」)が API 上に存在しないことは普通にある。
  • 税区分:GET /taxes/codesその事業所の実コードを取得(コードは事業所ごとに異なる)。インボイス経過措置は控除率が枝番(控80%/控50%…)で分かれ、時期で変わる点に注意(切替日をコード側に反映する運用を決めておく)。
  • 会社/事業所 ID:GET /companies で API 用の ID を確定(画面表示の「事業所番号」と API の company_id は別物のことがある)。

二重登録の防止

会計への書き込み(取引登録)は 冪等ガード必須。

  • 「同一案件で成功済みなら再実行を拒否」を DB で判定。
  • 非冪等 POST(取引作成)は 失敗時に自動リトライしない(コミット後の 5xx/タイムアウトで二重登録になる)。リトライは 401(副作用前のトークン失効)だけに限定するか、人手の再送に寄せる。
  • 既定は DRY-RUN(実書き込みしないシミュレーション)にし、本番書き込みは管理者権限+段階導入(テスト1件を実登録して担当が実画面で確認)。

チェックリスト

  • リフレッシュトークンを env でなく DB に置き、更新のたびに書き戻す
  • access_token は期限+マージンでキャッシュ
  • マスタ(勘定科目/税区分/会社ID)は API から取得し、担当に実在名から選定させる
  • 取引登録は冪等ガード+非冪等 POST は無闇にリトライしない
  • 既定 DRY-RUN、本番は管理者のみ+テスト1件で実画面確認

よくある質問

「ローテーションするOAuth2リフレッシュトークンをDB永続化して壊れないようにする型」とは何ですか?

freee/Google等でリフレッシュトークンがローテーションし env固定だと初回更新後に必ず壊れる問題を、トークンをDBに持ち更新のたび書き戻す型で解決。マスタID取得・冪等ガード・段階導入まで含む会計API連携の定石。

どれくらいトークン(費用)を節約できますか?

ゼロから開発すると約9,000トークンかかりますが、この巻物を使えば約1,500トークンで済みます。差し引き約7,500トークン(API料金換算で約11円)・83%の節約です。

どうやって使いますか?

無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。

どのAIツールに対応していますか?

claude-code、cursor、codex-cli に対応しています。

商用利用できますか?

ライセンスは「商用利用可 (再販不可)」です。

🤝 自分でAIを動かすのは、まだ不安…という方へ

この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。

AI代行堂を見る →

関連する巻物

この巻物、誰かのトークンも救えます

𝕏 で節約レシートをシェア