GitHub Appの基礎
GitHub Appは、GitHubのAPI・Webhookと統合して自動化ツールやボット、サービス連携を実現するための公式なアプリケーション統合の仕組みです。細かな権限制御(Fine-grained permissions)と独自の認証フローを持ち、OAuth Appよりもセキュリティ面で優れた設計になっています。
GitHub AppとOAuth Appの違い
GitHubの統合には大きく2種類の方法があります。
| 比較項目 | GitHub App | OAuth App |
|---|---|---|
| 操作主体 | Bot(システム)として動作 | ユーザーとして動作 |
| 権限スコープ | Fine-grained permissions(詳細制御) | OAuth scopes(粗いスコープ) |
| アクセス範囲 | リポジトリ単位でのインストール | ユーザーが認可した範囲全体 |
| トークン種 | Installation Access Token | User-to-Server Token |
| レートリミット | インストールごとに5,000 req/h | ユーザーごとに5,000 req/h |
| Webhookサポート | アプリ単位で設定可能 | 制限あり |
| Marketplace公開 | 可能 | 可能 |
GitHubはGitHub Appを推奨しており、新規統合の開発にはGitHub Appを使用することがベストプラクティスです。
主要な概念
App Owner
GitHub AppはOrganizationまたは個人アカウントが所有します。所有者がAppの設定(権限、Webhook URL、Private Keyなど)を管理します。
Installation
ユーザーまたはOrganizationがGitHub Appを「インストール」することで、特定のリポジトリ(またはすべてのリポジトリ)へのアクセスが許可されます。1つのAppに対して複数のInstallationが存在できます。
Private Key
GitHub AppはRSA秘密鍵を使ってJWT(JSON Web Token)を生成します。この秘密鍵はApp Ownerのみが保持し、安全に管理する必要があります。
Installation Access Token
GitHub AppがAPIを呼び出すために使用する短命(1時間)のトークンです。JWTを使ってGitHub APIにリクエストすることで発行されます。
認証フロー
GitHub Appの認証は2ステップで行われます。
ステップ1: JWT生成
GitHub AppのIDとRSA秘密鍵を使ってJWTを生成します。JWTの有効期限は最長10分です。
import { createAppAuth } from "@octokit/auth-app";
import { Octokit } from "@octokit/rest";
const auth = createAppAuth({
appId: process.env.GITHUB_APP_ID,
privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
});
// JWT(App認証)でOctokitを初期化
const appOctokit = new Octokit({
authStrategy: createAppAuth,
auth: {
appId: process.env.GITHUB_APP_ID,
privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
},
});
ステップ2: Installation Access Token取得
JWTを使って特定のInstallationに対するAccess Tokenを取得します。
// Installation IDを指定してAccess Token取得
const installationOctokit = await appOctokit.auth({
type: "installation",
installationId: Number(process.env.GITHUB_APP_INSTALLATION_ID),
});
// Installation Access Tokenを使ったAPIコール
const octokit = new Octokit({ auth: installationOctokit.token });
const { data } = await octokit.rest.repos.listForInstallation();
Webhookによるイベント処理
GitHub Appは、インストールされたリポジトリで発生するイベント(push、pull_request、issuesなど)をWebhookで受信できます。受信したWebhookのペイロードは署名(X-Hub-Signature-256ヘッダー)で検証する必要があります。
import { createHmac, timingSafeEqual } from "crypto";
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature =
"sha256=" +
createHmac("sha256", secret).update(payload).digest("hex");
// タイミング攻撃を防ぐためtimingSafeEqualを使用
return timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// Express.jsでのWebhookエンドポイント例
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-hub-signature-256"] as string;
const payload = req.body.toString("utf8");
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Unauthorized");
}
const event = req.headers["x-github-event"];
const body = JSON.parse(payload);
if (event === "pull_request" && body.action === "opened") {
// プルリクエストが開かれたときの処理
console.log(`PR opened: ${body.pull_request.title}`);
}
res.status(200).send("OK");
});
Webhookのシグネチャ検証は必須です。=== による単純な文字列比較はタイミング攻撃に脆弱なため、必ず crypto.timingSafeEqual を使用してください。
GitHub Actionsでの活用
デフォルトの GITHUB_TOKEN の制限
GitHub Actionsのデフォルトトークン(secrets.GITHUB_TOKEN)にはいくつかの制限があります。
- クロスリポジトリアクセス不可: 他のリポジトリへのAPIコールができない
- ワークフロートリガー不可:
GITHUB_TOKENでトリガーしたイベントは新たなワークフローを起動しない(無限ループ防止のため) - 権限の固定: ワークフロー単位での細かな権限設定は限定的
GitHub Appトークンを使う方法
GitHub AppをActionsで活用することで上記の制限を回避できます。
name: Cross-repository operation
on:
push:
branches: [main]
jobs:
update-other-repo:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
# 別のリポジトリへのアクセスも指定可能
repositories: "other-repo"
- name: Use the token for API call
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
gh api repos/my-org/other-repo/dispatches \
--method POST \
--field event_type=deploy-triggered
actions/create-github-app-token アクション
actions/create-github-app-token はGitHub公式のアクションで、ワークフロー内でGitHub Appのインストールトークンを簡単に生成できます。
| 入力パラメーター | 説明 |
|---|---|
app-id | GitHub AppのID(vars.APP_ID として保存推奨) |
private-key | RSA秘密鍵(secrets として保存必須) |
owner | トークンの対象Organization/ユーザー(省略時は現リポジトリのOwner) |
repositories | アクセスするリポジトリ名(カンマ区切り) |
GitHub Appの作成手順
- アプリ登録: GitHubの設定画面(Settings > Developer settings > GitHub Apps > New GitHub App)から登録
- 基本設定: App名、Homepage URL、Webhook URLを入力
- 権限設定: 必要な最小権限のみを選択(最小権限の原則)
- 秘密鍵生成: アプリ作成後、「Generate a private key」でRSA鍵ペアを生成・ダウンロード
- インストール: Organization/リポジトリにAppをインストール
- シークレット設定: App ID、秘密鍵をCI/CDのシークレットに登録
秘密鍵(.pemファイル)は安全な方法で保管してください。GitHub ActionsではリポジトリシークレットまたはOrganizationシークレットとして登録し、環境変数経由でアクセスします。複数行の秘密鍵をシークレットに保存する場合は、改行を含めたまま貼り付けると正しく扱われます。
Permissions(権限)の種類
GitHub Appで指定できる主な権限カテゴリは以下の通りです。
| カテゴリ | 権限例 |
|---|---|
| リポジトリ | Contents, Pull requests, Issues, Actions, Deployments |
| Organization | Members, Projects |
| アカウント | Profile, Email addresses |
各権限には read(読み取り)、write(書き込み)、none(なし)の3段階があります。必要最小限の権限のみを付与することがセキュリティのベストプラクティスです。
まとめ
GitHub Appは、サービス・ボット統合に適した安全で柔軟な仕組みです。Fine-grained permissionsによる最小権限アクセス、JWTベースの認証、Webhookによるイベントドリブンな処理を組み合わせることで、堅牢な自動化を実現できます。GitHub Actionsのクロスリポジトリ操作やワークフロートリガー制御にも有効です。