Slackのtoken rotationでは、refresh tokenは再利用できる固定資格情報ではありません。Slack公式仕様ではrefresh tokenを使って新しいaccess tokenとrefresh tokenを取得し、利用済みrefresh tokenは失効します。更新結果から新しい組を保存しないまま古いrefresh tokenを並行利用すると、次の更新で失敗し、Slack APIへのアクセスが止まる原因になります。ここでは、installationごとのtoken pairを安全に更新する設計と、refresh失敗時の切り分けを説明します。
最初に確認するのは、アプリでtoken rotationが有効かどうか、どのinstallationのどのtoken typeを扱っているかです。Slackのtoken rotationはOAuth granular permissionsを使うSlack app向けの仕組みとして案内されています。rotation有効化後のaccess tokenは12時間で期限切れとなり、refresh tokenを用いて更新します。アプリ設定を有効にする前に、開発環境で期限切れ・更新・保存・再起動まで試してください。Slackのドキュメントは、一度有効にするとoffにできないと注意しています。既存システムへ後付けする場合は、実装の準備ができてから切り替える判断が必要です。
目次
【tokenの関係を把握する】
rotationではaccess tokenだけでなくrefresh tokenも状態として保存します。refresh成功応答には新しいaccess token、expires_in、refresh_token、token_type等が含まれます。古いrefresh tokenを新しいものへ置き換えることが必須です。token pairのうち片方だけを更新すると、access tokenは使えるのに次回refreshができない、または有効なrefresh tokenを失うという不整合が起こります。installation ID、token type、access token、refresh token、expires_at、scopeなど、運用上必要な情報を明確な単位で管理します。secret値を通常のログや分析イベントに出さないことも前提です。
表は横にスクロールできます
| 保管項目 | 目的 | 注意点 |
|---|---|---|
| installation key | どのworkspace/app installationかを特定 | workspace名など可変の表示名だけを鍵にしない |
| token type | bot、user、app-level等を識別 | 型ごとの利用範囲を混同しない |
| access token | Slack API呼び出しに利用 | expires_atと併せて扱う |
| refresh token | 次のaccess tokenを取得 | 一度使ったtokenを再利用しない |
| expiration | 更新期限の判断 | expires_inから絶対時刻を計算し時計差を考慮 |
| credential version | 保存世代を判別 | stale workerによる古い値の上書きを検出 |
これは実装例であり、Slackが定めた必須DB schemaではありません。既存のtoken storeがある場合は、同等の対応関係を作れるか確認してください。
【並行refreshを防ぐ】
失敗の典型は、期限到来時に複数のAPI requestやworkerが同じinstallationのaccess tokenを検知し、同じrefresh tokenで同時にoauth.v2.accessを呼ぶことです。refresh tokenは使い捨てなので、一方の応答が新token pairを返したあと、もう一方が古いrefresh tokenを使うと失敗し得ます。さらに、遅れて返ったworkerが古いtoken pairをDBへ書き戻すと、最新の組が失われます。
installation単位のsingle-flightまたは分散lockを使い、refresh中は他のcallerに同じ更新をさせない設計にします。ロック取得後にDBを再読込し、すでに別workerがaccess tokenを更新していないか確認します。更新済みなら新しいaccess tokenを使い、再refreshしません。ロックは期限付きとし、プロセス停止後に永久に残らないようにします。複数リージョンや複数プロセスでは、プロセス内mutexだけでは排他にならないため、共有DB、分散lock、条件付き更新などの仕組みを検討します。
更新処理は次の順にすると競合を減らせます。
-
installationのtoken recordを読み、期限とversionを確認する。
-
installation単位でrefresh lockまたはleaseを取得する。
-
lock取得後にrecordを再読込し、他workerの更新がないか確認する。
-
現行refresh tokenでoauth.v2.accessへ一度だけ要求する。
-
成功時はaccess token・refresh token・expires_atをひとまとまりとして保存する。
-
保存時に読み取ったversionとの一致を条件にし、古いworkerの上書きを拒否する。
-
永続化を確認してからlockを解放し、待機callerへ更新結果を共有する。
API呼び出しが成功しても、その前にプロセスが停止して新しいpairを保存できなければ回復が難しくなります。保存処理は暗号化・アクセス制御されたデータストアで行い、保存失敗を「更新成功」と扱いません。新しいrefresh tokenは利用済みtokenを置き換えるため、後からログやメモリの古い値を再保存する経路がないか、token versionを使って検出してください。
【失敗の切り分け】
oauth.v2.accessの失敗をすべて「tokenが切れた」とまとめないでください。requestのclient credentials、grant_type、refresh token、content type、token type、ネットワーク応答、Slackの返却エラーを安全に確認します。Slack公式のtoken rotation guideはclient_id、client_secret、grant_type=refresh_token、refresh_tokenを送る更新例を示しています。API method referenceでは受け付ける形式やOAuth methodの情報が定義されるため、実際の実装と照合します。秘密値はログへ記録せず、エラー分類と相関IDだけを残します。
再試行は、refresh tokenがすでに消費された可能性を考慮して行います。timeoutが発生したとき、Slack側でrefreshが成功し新token pairを返したものの応答を受け取れなかった可能性があります。この状態で古いrefresh tokenを何度も呼び出すと失敗を重ねる場合があります。単純な無限retryを避け、保存済みtoken version、直近の更新ログ、Slack API応答を照合します。どちらが最新か確定できず、有効なpairが残っていない場合は、installationの再認証が必要か判断します。原因不明のまま全installationのtokenを削除するのは避け、対象installationに限定します。
エラーが発生したときは次の順に確認します。
-
対象installationとtoken typeが正しいか。
-
rotationを有効にした時期と、旧long-lived tokenをexchange済みか。
-
保存したexpires_atと実際のAPIエラーにずれがないか。
-
client credentials、grant_type、送信形式が正しいか。
-
同一installationに同時refreshが走っていないか。
-
成功応答の新しいrefresh tokenが完全に保存されたか。
-
遅いworkerや再試行処理が古いpairを書き戻していないか。
-
最新pairを特定できない場合、対象installationの再認証が必要か。
【障害時の復旧と再認証】
Slack公式Docsでは、refresh tokenは一度だけ使用でき、交換後に以前のtokenは短い猶予期間の後に失効すると説明されています。最初の長期tokenをrotation用にexchangeする操作も、同じaccess tokenを何度もexchangeするものではありません。すでに一度exchangeした長期access tokenを再exchangeしようとしたり、元のrefresh tokenを繰り返し使用したりしないでください。
有効な新token pairが保存されているなら、そのpairで更新を再開し、token storeのversionと更新時刻を確認します。pairが不明・破損しているなら、同じ古いrefresh tokenを自動再試行し続けず、再認証・再インストールが必要かをinstallation単位で判断します。Slack docsには、token exchange後に旧long-lived access tokenが失効することや、再exchange・revokeの扱いに注意事項があります。復旧手順を運用Runbookに書く前に、現在の公式手順とアプリの配布形態を確認してください。
【導入前テスト】
開発workspaceで次を検証します。
□ token rotationが有効なinstallationを識別できる
□ expires_inから期限を記録し、期限前に更新を開始する
□ 同じinstallationへの同時refreshが1回に集約される
□ 成功応答のaccess/refresh pairを一括保存できる
□ DB保存失敗時に成功状態へ進まない
□ stale workerが古いpairを書き戻せない
□ refresh timeout時に無条件の無限retryをしない
□ credentialやresponse bodyのtokenをログへ出さない
□ process restart後に最新pairでSlack APIを呼び出せる
□ token typeやinstallationを取り違えない
□ 期限切れ・無効tokenのエラー時に対象installationを特定できる
□ 再認証の要否と担当者が明確である
このチェックリストは検証計画であり、本稿作成時に実際のSlack Appでtoken refreshを試した結果ではありません。テストは本番利用者や本番installationではなく、分離したdevelopment workspaceで行い、実際に更新後のpairが永続化されるところまで確認します。
【運用設計の要点】
Slackの公式仕様で決まるのは、refresh手順やtokenの一回利用、期限などの製品挙動です。single-flight、lock、version付き保存、stale worker防止、アラートや再認証Runbookは、それらの制約を踏まえたアプリ側の設計です。仕様と設計提案を混同せず、どの保証がSlackから提供され、どの障害対策を自分たちで実装するのか分けて記録します。
監視では、refresh成功率、期限切れ前の更新率、oauth.v2.accessのエラー分類、lock競合、token store書き込み失敗、stale write拒否、再認証が必要なinstallation数を見ます。token本体を記録せず、installation識別子も必要最小限にします。広範な失敗が起きたら、まず新規refreshの競合を止め、保存済みtoken pairの世代を確認します。最も新しい成功応答からpairを復元し、対象installationを限定して再認証を検討します。
【結論】
安全なtoken rotationの鍵は、refresh tokenを一度だけ使うものとして扱い、installationごとに更新を直列化し、応答で返るaccess/refresh pairを原子的に保存することです。並行request、timeout、DB書き込み失敗、遅れて戻るworkerをテストし、古いpairが復活しないことを確認します。更新状態が曖昧なときに古いrefresh tokenを繰り返し投げるのではなく、保存履歴から最新pairを特定し、できなければ該当installationの再認証へ進む設計にしてください。
Sources
-
Slack, Using token rotation (確認日 2026-10-15): https://docs.slack.dev/authentication/using-token-rotation/(新しいタブで開く)
-
Slack, oauth.v2.access method (確認日 2026-10-15): https://docs.slack.dev/reference/methods/oauth.v2.access/(新しいタブで開く)
Editorial Note
本文ではSlackのtoken rotation仕様と、競合・障害に備えるアプリ側の設計推奨を分けています。refresh実行や実環境の動作確認は行っていません。
