Slack Bot Token(xoxb-で始まる文字列)は、Slackアプリのボットユーザーとして Web API を呼ぶための認証情報で、アプリをワークスペースへインストールした時点で発行されます。この記事では、Bot Tokenの発行と確認の手順、auth.testとx-oauth-scopesヘッダでトークンの持ち主と権限を確かめるコード、12時間で失効させるトークンローテーションの仕様、そして漏えいしたときにauth.revokeで止めるまでを、Slack公式ドキュメントの記述に沿って実装の順に整理します。slack api token や slack_bot_token という環境変数名で調べている方にも、そのまま設定に使える形でまとめました。
まとめ:Slack Bot Tokenで最初に決める発行経路と保管先と失効の手順
社内の単一ワークスペースで動かすBotなら、管理画面のOAuth & Permissionsで発行したxoxbを1本だけ使い、本番はSecrets Managerなどの秘密情報の保管サービスへ置きます。複数の顧客ワークスペースへ配るアプリは、oauth.v2.accessの応答からワークスペースごとのxoxbを受け取ってデータベースに保存する形になります。
起動時にはauth.testを呼び、bot_idが返ることと必要なスコープが付いていることを確かめてから処理を始めます。設定の取り違えはここで止まります。
トークンローテーションは一度有効にすると戻せず、アクセストークンの有効期限は12時間です。入れるのはBoltの組み込みOAuthを使う配布アプリだけで、固定トークンの社内BotではIP制限と失効手順の整備を優先します。漏えい時はauth.revokeで無効化し、再インストールで取り直します。
Slack Bot Token(xoxb)の正体とユーザー・アプリレベルとの用途差
xoxbはボットユーザーに紐づきインストール単位で発行されるトークン
Bot Tokenは、アプリに付いたボットユーザーの権限で動くトークンです。アプリ自身の名前で投稿し、招待されたチャンネルの範囲で読み書きするため、担当者が退職しても止まりません。
公式のTokensのリファレンスでは、ボットトークンに既定の有効期限は無く、ローテーションは任意で有効にできると説明されています。期限が無いぶん、流出後も無効化するまでは使用可能な状態です。Web APIとEvents APIの役割分担など全体像はSlack APIとは?Web API・Events API・Boltの違いと実装手順に譲り、ここではトークンの発行から失効までに絞ります。
xoxp・xapp・xoxe・xwfpの接頭辞で見分けるトークン種別の一覧表
設定ファイルに貼られた文字列がどの種類かは、先頭の接頭辞で判別できます。Tokensのリファレンスに載っている種別を、取得場所と寿命で並べると次のとおりです。
| 接頭辞 | 種類 | 取得する場所 | 寿命 |
|---|---|---|---|
xoxb- |
ボットトークン | インストール時に発行 | 既定は無期限 |
xoxp- |
ユーザートークン | 認可した利用者ごとに発行 | 既定は無期限 |
xapp- |
アプリレベルトークン | Basic Informationで作成 | 既定は無期限 |
xoxe.付き |
ローテーション後のアクセストークン | 更新APIの応答 | 12時間 |
xoxe- |
リフレッシュトークン | 更新APIの応答 | 1回だけ使える |
xwfp- |
ワークフロートークン | 関数の実行時に付与 | 最長15分 |
Socket Modeの接続はxapp、Web APIの呼び出しはxoxbです。この2本を逆に設定すると、Boltは起動直後に認証エラーで落ちます。xwfpはワークフローの関数ステップ専用で、15分経つかステップが終わると失効し、更新もできません。
Bot Tokenを発行して管理画面のOAuth設定で確認するまでの手順
Bot Token Scopesを足してワークスペースへインストールする4工程
社内の1ワークスペースで使うBotなら、管理画面の操作だけでxoxbが手に入ります。順番は次の4工程です。
- api.slack.comのアプリ一覧で「Create New App」を押し、アプリ名とワークスペースを決める
- 「OAuth & Permissions」の Bot Token Scopes に、投稿なら
chat:writeのように必要なスコープだけを追加する - 同じ画面で「Install to Workspace」を押し、ワークスペースの管理者として許可する
- 「OAuth Tokens」欄に表示された Bot User OAuth Token(xoxb-…)をコピーし、秘密情報の保管先へ登録する
発行済みトークンの確認も手順4と同じ画面で行います。Botとしてイベントを受ける設定(App Manifestやイベント購読)は、Slack Botの作り方:Bolt for Pythonでメンション返信からLambda運用までの手順と組み合わせてください。
スコープ追加後の再インストールで権限が積み上がる仕組みと注意点
途中でスコープを足した場合、再インストールを済ませるまで新しいスコープはトークンに反映されません。
見落としやすいのは削る方向です。OAuthによるインストールの解説には、スコープは既存の付与分に追加される方式で、トークンのスコープを下げることはできず、外すにはトークンを失効させるしかないと書かれています。試しにchannels:historyを付けたまま本番に出すと、使わない権限も無期限のトークンに付与されたままです。検証用と本番用でアプリ自体を分け、本番には必要なスコープだけを付けます。
配布アプリでoauth.v2.accessの応答からxoxbとxoxpを受け取る流れ
複数のワークスペースへ配るアプリは、管理画面からトークンをコピーできません。利用者が「Add to Slack」から許可すると、アプリのリダイレクト先にcodeが返り、それをoauth.v2.accessに渡して交換します。
応答のトップレベルにあるaccess_tokenがxoxbで、token_typeはbotです。ユーザースコープも要求していれば、authed_user.access_tokenにxoxpが入ります。team.idとbot_user_idを一緒に保存しておくと、イベント受信時にどのワークスペースのトークンを使うか引けます。
client_idとclient_secretはHTTP Basic認証で渡す方法が推奨されており、client_secretもxoxbと同じく保管先から読み込みます。
auth.testとx-oauth-scopesでトークンの持ち主と権限を確かめる実装
curlでauth.testを呼びbot_idとteam_idを確認する疎通コマンド
手元のトークンが生きているか、どのワークスペースのどのBotのものかは、auth.testで確かめます。スコープは不要で、公式に記載された呼び出し上限は1分あたり数百回です。トークンはURLのクエリではなく、Authorization: Bearerヘッダで渡します。
# 環境変数に入れたxoxbで疎通を確認する(-iで応答ヘッダも表示する)
curl -s -i -X POST https://slack.com/api/auth.test \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}"
成功すると本文に"ok": trueと、team・team_id・user_id・bot_idが返ります。bot_idはボットトークンで呼んだときにだけ含まれるため、xoxpを誤って設定したかどうかはこの項目の有無で判別できます。
応答ヘッダのx-oauth-scopesには、そのトークンが今持っているスコープがカンマ区切りで入ります。OAuthの解説にあるとおり、このヘッダはWeb APIのすべての応答に付くため、権限不足の調査では最初に見る場所です。
Pythonのslack_sdkで起動時にトークンを検証し誤設定で止めるコード
本番では、Botの起動時に同じ確認をコードで行い、条件を満たさなければその場で終了させます。間違ったトークンのまま常駐させると、最初の投稿で失敗するまで誰も気付きません。
import os
import sys
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
# このBotが使うスコープ(App Manifestと同じ内容にそろえる)
REQUIRED_SCOPES = {"chat:write", "app_mentions:read"}
def verify_bot_token() -> dict:
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
try:
res = client.auth_test()
except SlackApiError as e:
# invalid_auth や token_revoked はここで捕まえて起動を止める
sys.exit(f"Slackトークンの検証に失敗しました: {e.response['error']}")
if not res.get("bot_id"):
sys.exit("ボットトークン(xoxb)ではないトークンが設定されています")
# ヘッダ名の大文字小文字は実装差があるため小文字にそろえて読む
headers = {k.lower(): v for k, v in res.headers.items()}
granted = {s.strip() for s in headers.get("x-oauth-scopes", "").split(",") if s.strip()}
missing = REQUIRED_SCOPES - granted
if missing:
sys.exit(f"スコープが不足しています: {sorted(missing)}(追加後に再インストールが必要)")
# 余分なスコープは警告だけ出す(外すにはトークンの失効が必要なため)
extra = granted - REQUIRED_SCOPES
if extra:
print(f"警告: 使っていないスコープがあります: {sorted(extra)}")
return {"team_id": res["team_id"], "bot_id": res["bot_id"]}
if __name__ == "__main__":
print(verify_bot_token())
余分なスコープを止めずに警告に留めているのは、前の章のとおりスコープはトークンから外せないためです。警告が出たら、検証用アプリとの取り違えや、試験で足したスコープの残りを疑います。
invalid_authなどauth.testが返すエラーの意味と原因
"ok": falseのときはerrorの値で原因を切り分けます。公式の定義をBot運用で起きやすい場面に置き換えると次のとおりです。
invalid_auth:トークンが無効、またはIP許可リスト外からの呼び出しnot_authed:トークンが渡っていない(環境変数名の綴り違いなど)account_inactive:ボットユーザーやワークスペースが削除済みtoken_revoked:ユーザートークンで、利用者やアプリが削除されたtoken_expired:ローテーション有効のトークンが12時間を過ぎた
見落としやすいのはinvalid_authの2つ目の意味です。IP制限を設定した直後にCIなど許可外の場所から呼ぶと、トークンが正しくてもこのエラーになります。
トークンローテーションを有効化する前に確認する12時間失効の運用条件
有効化すると元に戻せずアクセストークンが43200秒で失効する仕様
トークンローテーションの公式ガイドによると、有効にしたアプリではアクセストークンのexpires_inが43200秒(12時間)になり、期限内にリフレッシュトークンで新しいトークンへ取り替え続ける必要があります。ガイドには、一度有効にしたローテーションは無効に戻せないと明記されています。
設定場所は、Marketplace未公開のアプリならOAuth & Permissions、App Manifestならsettings.token_rotation_enabled: trueです。既に発行済みの無期限トークンはoauth.v2.exchangeで期限付きのトークンとリフレッシュトークンへ交換します。最初の更新が成功した時点で元の無期限トークンは使えなくなるため、交換後にauth.testで旧トークンが無効になったことを確かめます。このとき旧トークンをauth.revokeで消してはいけません。公式は、利用者に再インストールを強いることになると注意しています。
リフレッシュトークンという仕組みの一般論や寿命の設計は、リフレッシュトークンとは?トークンローテーションの仕組みと更新フローで扱っています。
oauth.v2.accessにrefresh_tokenを渡して更新するリクエスト例
更新は、grant_type=refresh_tokenを付けてoauth.v2.accessを呼ぶだけです。公式ガイドの例を、秘密情報を環境変数から読む形にすると次のようになります。
# ローテーション有効のトークンを更新する(応答の refresh_token は必ず保存し直す)
curl -s -X POST https://slack.com/api/oauth.v2.access \
-u "${SLACK_CLIENT_ID}:${SLACK_CLIENT_SECRET}" \
-d grant_type=refresh_token \
-d refresh_token="${SLACK_REFRESH_TOKEN}"
応答には新しいaccess_token(xoxe.付き)、expires_in、新しいrefresh_tokenが入ります。リフレッシュトークンは1回限りの設計で、使用済みのものは短い猶予の後には無効です。古い値を保存したままにすると、次の更新で失敗します。
もう1つの制約は同時に有効なトークンの数です。12時間以内に更新を繰り返しても有効なアクセストークンは最大2本までで、3本目ができると古いものから失効します。複数のサーバーがそれぞれ勝手に更新すると互いのトークンを失効させるので、更新処理は1か所に集め、期限切れの前に予定実行で回します。
Boltの組み込みOAuthなら自動で更新され固定トークン構成では自作になる理由
Bolt for Pythonのトークンローテーションの解説には、v1.7.0以降で、組み込みのOAuth機能を使っている場合に限り自動で更新すると書かれています。
App(token=os.environ["SLACK_BOT_TOKEN"])のように固定のxoxbを渡す社内Botは、この対象外です。ローテーションを入れるなら、前の項の更新処理と、新しい値を書き戻せる保管先(Secrets Managerなど)を自前で用意します。環境変数は実行中に書き換えられません。
漏えいを防ぐ保管先とIP制限と、流出時にauth.revokeで止める手順
.envは開発用に留め本番は秘密情報の管理サービスへ置く線引き
Slackのセキュリティのベストプラクティスは、保管先を開発と本番で分けています。開発はローカルの.envに置いて.gitignoreで誤コミットを防ぎ、本番はGitHub Actions Secrets、AWS Secrets Manager、HashiCorp Vaultのような管理サービスを使う、という線引きです。
同じページには、ソースコードへの直書き、ブラウザ側のコードへの配置、GETのクエリ文字列での受け渡しを避けることも書かれています。配布アプリはトークンをワークスペースと利用者に紐づけて保存し、アンインストール後は本番とバックアップの両方から消します。
Restrict API Token Usageで送信元IPを最大20件に絞る設定の制約
トークンが流出しても、許可したサーバー以外からは使えないようにできます。OAuth & Permissionsの「Restrict API Token Usage」で、Web APIを呼べる送信元IPを登録する機能です。公式の説明には次の制約があります。
- 登録は最大20件で、1件ごとにCIDR範囲か単一のIPアドレスを指定する
- ローカルのIPアドレスは登録できず、IPv6には対応していない
- 許可リスト外からの呼び出しは
invalid_authで拒否される - Incoming Webhookには適用されない
出口IPを固定したNATゲートウェイ経由のサーバーなら入れやすく、出口IPが変わるサーバーレス環境からの呼び出しは拒否されます。Slack Incoming WebhookのURLはこの制限の外にあるので、別に守る必要があります。
secret scanningとauth.revokeで流出したxoxbを止める手順
GitHubのsecret scanningの対応パターン一覧では、slack_api_tokenがPartner(提供元への通知)、User alert、Push protection、Validity checkのすべてで対象になっています。リポジトリでPush protectionを有効にしておけば、xoxbを含むコミットを止めるタイミングはpushの段階です。GitHub上の別のトークンの扱いはGitHub PATの作成方法と失効も参考になります。
それでも流出に気付いたときは、次の順で止めます。
- 流出したトークンでauth.revokeを呼び、応答の
revokedがtrueであることを確かめる(test=1を付けると失効させずに試せる) - Slackのアクセスログやアプリの実行ログで、流出後に不審な投稿や読み取りが無かったかを確認する
- ワークスペースへ再インストールして新しいxoxbを発行し、保管先の値を差し替える
- ボットを参加させていたチャンネルへ招待し直し、auth.testで新しいトークンを検証する
手順4が要るのは、ボットトークンを失効させるとボットユーザーが非アクティブになり、チャンネルの参加も外れるためです(アプリ自体はアンインストールされません)。通知先のチャンネル一覧を設定ファイルに残しておくと、復旧が早まります。
Bot Tokenで済ませる場面とユーザートークンやローテーションが要る場面の判断基準
ユーザートークン(xoxp)を採用する条件と社内Botで見送る理由
社内の通知や問い合わせ対応のBotはxoxbだけで作り、xoxpは使いません。xoxpは認可した個人の権限で動くため、その人の非公開チャンネルやDMまで届く範囲が広がり、退職や異動で認可が外れるとBotごと止まります。
xoxpを採用するのは、本人のステータスを予定表と同期するなど、本人名義の操作が要件そのものの場合に限ります。その場合もユーザースコープは機能ごとに絞り、Botの処理とは兼用しません。
ローテーションを入れる条件と社内の単一ワークスペースで見送る判断
ローテーションを入れるのは、複数の顧客ワークスペースへ配るアプリをBoltの組み込みOAuthで作る場合です。更新はライブラリが受け持ち、流出したトークンが使える時間を12時間に縮められます。顧客のセキュリティ審査で期限付きトークンを求められる案件でも採用します。
固定トークンで動く社内Botには入れません。有効化を取り消せないうえ、更新処理と書き戻し、同時更新の制御を自作することになり、不具合があるとBotが12時間ごとに止まります。この規模なら、管理サービスへの格納、IP制限、Push protection、auth.revokeの手順書の4点を整えるほうが少ない工数で済みます。
Slackを社内の基幹システムやSaaSとつなぐ連携で、トークンの保管や更新、失効の仕組みまで含めて設計を任せたい場合は、API開発・システム連携でご相談を受け付けています。
よくある質問
Slack Bot Tokenについて、確認方法や有効期限、再発行など、検索の多い質問に答えます。
Slack Bot Tokenはどこで確認できますか?
api.slack.comのアプリ一覧から対象アプリを開き、「OAuth & Permissions」の「OAuth Tokens」欄に表示される Bot User OAuth Token がxoxbです。欄が空なら未インストールです。手元の文字列がどのアプリのものか分からないときは、auth.testで返るteamとbot_idで特定します。xappは「Basic Information」の画面にあります。
Bot Tokenに有効期限はありますか?
トークンローテーションを有効にしていなければ、xoxbに有効期限はありません。auth.revokeで失効させるか、アプリをアンインストールするまでは利用可能です。ローテーションを有効にしたアプリでは、アクセストークンは発行から12時間(43200秒)で切れ、リフレッシュトークンで取り替え続ける必要があります。期限が無いぶん、保管先とIP制限で守る前提で運用します。
Bot Tokenを再発行するにはどうすればよいですか?
auth.revokeで今のトークンを失効させてから、アプリをワークスペースへ再インストールすると新しいxoxbが発行されます。失効させるとボットユーザーがチャンネルから外れるため、再発行後に招待し直すことと、保管先の値を差し替えることを手順に含めてください。
SLACK_BOT_TOKENとSLACK_APP_TOKENは何が違いますか?
SLACK_BOT_TOKENにはxoxbを入れ、メッセージの投稿などWeb APIの呼び出しに使います。SLACK_APP_TOKENにはxappを入れ、Socket ModeでSlackとWebSocket接続を張るために使います。xappにはconnections:writeのスコープが必要です。Socket Modeを使わずHTTPでイベントを受ける構成なら、SLACK_APP_TOKENは不要で、代わりに署名検証用のSLACK_SIGNING_SECRETを設定します。
Bot TokenをGitHub Actionsで使うときはどこに置けばよいですか?
リポジトリのGitHub Actions Secretsに登録し、ワークフローでは${{ secrets.SLACK_BOT_TOKEN }}のように参照します。Slackのセキュリティのベストプラクティスでも、本番の保管先の例としてGitHub Actions Secretsが挙がっています。Restrict API Token Usageを設定している場合、GitHubがホストする実行環境のIPは許可リストに収まらないことが多く、呼び出しがinvalid_authになる点に注意してください。
関連記事
- Slack APIとは?Web API・Events API・Boltの違いと実装手順:トークンを使うWeb APIとEvents APIの全体像と、受信方式の選び分け
- Slack Botの作り方:Bolt for Pythonでメンション返信からLambda運用まで:発行したxoxbとxappでBotを動かす実装手順
- Slack MCPサーバーの接続手順と権限設計:AIエージェントにSlackを操作させる場合のトークンと権限の考え方
- Slackワークフローの作り方:フォーム・条件分岐・変数・Webhookの設定:トークンを扱わずに済むノーコードの自動化との境界