GitHub App
GitHub App とは
GitHub App は、GitHub 上で動く自動化をひとつの独立した主体として登録する仕組みです。「PR を自動で作る」「Issue にラベルを付ける」「コミットの検査結果を返す」といった処理を、特定の人のアカウントではなくアプリの名義で実行できます。
個人アクセストークン(PAT)で同じことをすると、その人が退職した瞬間に自動化が止まり、権限もその人の全リポジトリに及びます。GitHub App はこの2つを解決します。
| 方式 | 主体 | 権限の粒度 | 有効期限 |
|---|---|---|---|
| 個人アクセストークン | 個人 | スコープ単位(広い) | 設定次第。長期になりがち |
| OAuth App | 認可した個人の代理 | スコープ単位 | ユーザーが取り消すまで |
| GitHub App | アプリ自身 | リポジトリごと・権限ごとに細かく | トークンは1時間 |
[[OAuth・OIDC]] の OAuth App と名前が似ていますが、OAuth App は「ユーザーの代わりに動く」もの、GitHub App は「アプリとして動く」ものです。
認証は2段階
GitHub App の認証は、[[JWT]] と短命トークンの交換で成り立ちます。
- App JWT を作る — アプリ登録時に得た秘密鍵で、
iss(App ID)・iat・expを持つ JWT に RS256 で署名する。有効期限は最長10分 - Installation token に交換する — その JWT を
Authorization: Bearerに付けてPOST /app/installations/{installation_id}/access_tokensを呼ぶと、1時間だけ有効なトークンが返る - 以後の API 呼び出しは、この Installation token で行う([[GitHub REST API活用パターン]])
const jwt = signRS256({ iss: APP_ID, iat: now - 60, exp: now + 540 }, privateKey)
const res = await fetch(`https://api.github.com/app/installations/${INSTALLATION_ID}/access_tokens`, {
method: 'POST',
headers: { Authorization: `Bearer ${jwt}`, Accept: 'application/vnd.github+json' },
})
const { token, expires_at } = await res.json()
長期の秘密は秘密鍵1つだけで、実際に API を叩くトークンは短命です。これは [[短期クレデンシャル]] の考え方そのもので、トークンが漏れても被害は1時間で終わります。
権限とインストール範囲
権限は「Contents: 読み書き」「Pull requests: 読み書き」「Issues: 読み取り」のように機能単位で最小に選びます。[[最小権限の原則]] をそのまま適用でき、PR を作るだけのアプリに Actions や Secrets の権限を付ける理由はありません。
もう1つ重要なのがインストール範囲です。アプリはアカウント(個人または Organization)に「インストール」して初めてリポジトリへ届き、その際に「全リポジトリ」か「選んだリポジトリだけ」かを決めます。既定が「全リポジトリ」になっている場面があり、意図せず全部に権限が及ぶことがあります。インストール後に repository_selection が selected になっているかを確認します。この範囲の変更だけは API では行えず、設定画面から操作します。
作る手順
手作業で作るなら、Settings > Developer settings > GitHub Apps から名前・権限・Webhook の有無を入力し、生成された秘密鍵をダウンロードします。
自動化したいなら manifest flow が使えます。権限や Webhook 設定を JSON(manifest)で書き、https://github.com/settings/apps/new へ POST すると、作成確認の画面が出ます。ユーザーが「Create」を押すとリダイレクトで一時コードが返り、それを POST /app-manifests/{code}/conversions に渡すと App ID・秘密鍵・Webhook secret が API 応答で返ります。ブラウザ操作は「Create」と「Install」の2クリックだけで、残りはスクリプトにできます。
Installation ID は、App JWT を使って GET /repos/{owner}/{repo}/installation を呼ぶと分かります。
運用でつまずくところ
- 秘密鍵の形式 — GitHub が配る鍵は PKCS#1 で、Web Crypto で読む環境では PKCS#8 への変換が要る。[[秘密鍵のファイル形式(PEM・PKCS#1・PKCS#8)]] に手順がある
- 時計のずれ — JWT の
iatがサーバーの時計より未来だと拒否される。iatを60秒ほど過去にずらすのが定石 - トークンの再利用 — 1時間ごとに交換すればよいが、有効期限ぎりぎりで使うと途中で切れる。数分の余裕を見て更新する
- レートリミット — Installation token の上限はインストール先のリポジトリ数やユーザー数で増減する。[[レートリミット]] の残量を応答ヘッダーで確認する
- Webhook を使わない構成でもよい — 定期実行や外部からの呼び出しで動くだけなら Webhook は無効で作れる。受け口を増やさないほうが攻撃面も小さい
初学者向けポイント
- まず「誰の名義で動くべきか」を考えます。人の代理なら OAuth App、Bot として動くなら GitHub App です
- 秘密鍵は1つの長期秘密なので、環境変数やシークレットストアに置き、リポジトリには入れません
- 「PR を作るのに必要な権限は何か」を1つずつ足していくと、結果として最小権限になります。最初から広く付けて後で削るのは難しいです
関連技術とのつながり
- [[GitHub REST API活用パターン]] — Installation token で呼ぶ API 側の作法
- [[JWT]] — App JWT の署名と有効期限
- [[OAuth・OIDC]] — 「人の代理」で動く OAuth App との違い
- [[Webhook]] — イベント駆動で動かすときの受け口
- [[短期クレデンシャル]] — 1時間トークンの設計思想
- [[GitHub Actionsカスタムaction自作]] — ワークフロー内から GitHub App のトークンを使う場面
- [[最小権限の原則]] — 権限とインストール範囲の決め方
- [[秘密鍵のファイル形式(PEM・PKCS#1・PKCS#8)]] — 配られる鍵をそのまま読めない環境への対処
Q: GitHub App の認証で、API を実際に呼ぶときに使うトークンはどれ?
- [ ] 秘密鍵で署名した App JWT をそのまま使う
- [x] App JWT を交換して得た、1時間有効な Installation token
- [ ] アプリ作成者の個人アクセストークン
解説: App JWT は「トークンを発行してもらうため」の身分証で、API 呼び出しには Installation token を使います。
Q: 個人アクセストークンではなく GitHub App を使う利点として本文で挙げられているものはどれ?
- [x] 特定の人に依存せず、リポジトリごと・権限ごとに細かく絞れる
- [ ] レートリミットが無制限になる
- [ ] 秘密鍵が不要になる
解説: 退職や異動で自動化が止まらず、権限の粒度も細かくなります。秘密鍵は1つ必要です。
Q: インストール範囲について正しいものはどれ?
- [ ] 常に「選んだリポジトリだけ」になるので確認不要
- [x] 既定で「全リポジトリ」になることがあり、変更は API でなく設定画面からしか行えない
- [ ] インストール範囲は権限とは無関係なので気にしなくてよい
解説: 意図せず全リポジトリに権限が及ぶことがあるため、インストール後に repository_selection を確認します。