メインコンテンツまでスキップ

GitHub Appの基礎

GitHub Appは、GitHubのAPI・Webhookと統合して自動化ツールやボット、サービス連携を実現するための公式なアプリケーション統合の仕組みです。細かな権限制御(Fine-grained permissions)と独自の認証フローを持ち、OAuth Appよりもセキュリティ面で優れた設計になっています。

GitHub AppとOAuth Appの違い

GitHubの統合には大きく2種類の方法があります。

比較項目GitHub AppOAuth App
操作主体Bot(システム)として動作ユーザーとして動作
権限スコープFine-grained permissions(詳細制御)OAuth scopes(粗いスコープ)
アクセス範囲リポジトリ単位でのインストールユーザーが認可した範囲全体
トークン種Installation Access TokenUser-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で活用することで上記の制限を回避できます。

.github/workflows/cross-repo-example.yml
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-idGitHub AppのID(vars.APP_ID として保存推奨)
private-keyRSA秘密鍵(secrets として保存必須)
ownerトークンの対象Organization/ユーザー(省略時は現リポジトリのOwner)
repositoriesアクセスするリポジトリ名(カンマ区切り)

GitHub Appの作成手順

  1. アプリ登録: GitHubの設定画面(Settings > Developer settings > GitHub Apps > New GitHub App)から登録
  2. 基本設定: App名、Homepage URL、Webhook URLを入力
  3. 権限設定: 必要な最小権限のみを選択(最小権限の原則)
  4. 秘密鍵生成: アプリ作成後、「Generate a private key」でRSA鍵ペアを生成・ダウンロード
  5. インストール: Organization/リポジトリにAppをインストール
  6. シークレット設定: App ID、秘密鍵をCI/CDのシークレットに登録
ヒント

秘密鍵(.pemファイル)は安全な方法で保管してください。GitHub ActionsではリポジトリシークレットまたはOrganizationシークレットとして登録し、環境変数経由でアクセスします。複数行の秘密鍵をシークレットに保存する場合は、改行を含めたまま貼り付けると正しく扱われます。

Permissions(権限)の種類

GitHub Appで指定できる主な権限カテゴリは以下の通りです。

カテゴリ権限例
リポジトリContents, Pull requests, Issues, Actions, Deployments
OrganizationMembers, Projects
アカウントProfile, Email addresses

各権限には read(読み取り)、write(書き込み)、none(なし)の3段階があります。必要最小限の権限のみを付与することがセキュリティのベストプラクティスです。

まとめ

GitHub Appは、サービス・ボット統合に適した安全で柔軟な仕組みです。Fine-grained permissionsによる最小権限アクセス、JWTベースの認証、Webhookによるイベントドリブンな処理を組み合わせることで、堅牢な自動化を実現できます。GitHub Actionsのクロスリポジトリ操作やワークフロートリガー制御にも有効です。