🐙

octkitを利用せずにGitHub AppからAccess Tokenを取得する - TypeScript編 -

2024/08/21に公開

TL;DR

  • TypeScriptを使ってGitHub AppからAccess Tokenを取得する方法をまとめました
  • GitHubの公式が提供しているGitHub APIのラッパー(octkit)は利用しません
  • GitHub Appの作成方法などは参考記事を参照してください

参考記事

以下の神資料が一番わかりやすいので、参考にしてください(めちゃくちゃ助かりました🥹)
https://zenn.dev/tmknom/articles/github-apps-token

なぜ、octkitを利用しなかったのか

octkitのREADMEにも記載されていますが、
Node.js v16以降のモジュールシステムを利用するよう指示があります。

Important
As we use conditional exports, you will need to adapt your tsconfig.json by setting "moduleResolution": "node16", "module": "node16".
See the TypeScript docs on package.json "exports".
See this helpful guide on transitioning to ESM from @sindresorhus

octkitを利用するためにtsconfigの設定等は変更したくなかったため、今回はoctkitを利用せずに実装しました。

ソースコードの全貌

JWTの発行からAccess Tokenの取得
get-acctess-token.ts
import * as jwt from 'jsonwebtoken';

const main = async () => {
  const GITHUB_CLIENT_ID = "<< 作成したGitHub Appから参照してください >>"
  const GITHUB_PRIVATE_KEY = "<< 作成したGitHub AppからPrivateKeyを発行してください >>"
  const GITHUB_ORGANIZATION = "<< 対象のGitHub Organization名(必須ではありません) >>"

  const payload = {
    iat: Math.floor(Date.now() / 1000) - 1 * 60, // Issues 60 seconds in the past
    exp: Math.floor(Date.now() / 1000) + 1 * 60, // Expires 10 minutes in the future
    iss: GITHUB_CLIENT_ID,
  };

  const resultJwt = jwt.sign(payload, GITHUB_PRIVATE_KEY, {
    algorithm: 'RS256',
  });

  const uri = `https://api.github.com/app/installations`;
  const resultInstallation = await fetch(uri, {
    method: 'GET',
    headers: {
      Authorization: `Bearer ${resultJwt}`,
      accept: 'application/vnd.github+json',
      'X-GitHub-Api-Version': '2022-11-28',
    },
  });
  const installations = await resultInstallation.json();
  const installation = installations.find(
    (installation) => installation.account.login === GITHUB_ORGANIZATION,
  );

  if (!installation) {
    throw new Error('installation not found');
  }

  const resultAccessToken = await fetch(installation.access_tokens_url, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${resultJwt}`,
      accept: 'application/vnd.github+json',
      'X-GitHub-Api-Version': '2022-11-28',
    },
  });
  const accessToken = await resultAccessToken.json();

  console.info('token', accessToken.token);
}

簡単に解説

0. GitHub Appの作成

公式のドキュメントか紹介した参考記事を参照してください。
https://docs.github.com/ja/apps/creating-github-apps

1. ライブラリを利用してJWTを発行

GitHub AppからAccess Tokenを発行するには、JWT(JSON Web Token)が必要になります。
今回は、jsonwebtokenを利用してJWTを発行しました。

※ PrivateKey(秘密鍵)は発行すると<App名>.<作成日>.private-keyというファイル名でダウンロードできます。
※ 実装する際にはファイルを参照するか、ファイルの中身をコピーして利用してください。

  const payload = {
    iat: Math.floor(Date.now() / 1000) - 1 * 60, // Issues 60 seconds in the past
    exp: Math.floor(Date.now() / 1000) + 1 * 60, // Expires 10 minutes in the future
    iss: GITHUB_CLIENT_ID,
  };

  const resultJwt = jwt.sign(payload, GITHUB_PRIVATE_KEY, {
    algorithm: 'RS256',
  });

2. Installation APIを実行してInstallation IDを取得

GitHub AppからAccess Tokenを発行するには、Installation IDも必要となります。
Installation IDとは、GitHub Appをインストールした際に割り当てられるIDです。

APIを呼び出す際には、先ほど取得したJWTを利用します。

※ 返り値として、対象のGitHub Appがインストールされている先がすべて返却されます。

  const uri = `https://api.github.com/app/installations`;
  const resultInstallation = await fetch(uri, {
    method: 'GET',
    headers: {
      Authorization: `Bearer ${resultJwt}`,
      accept: 'application/vnd.github+json',
      'X-GitHub-Api-Version': '2022-11-28',
    },
  });
  const installations = (await resultInstallation.json());

3. Access Token APIを実行してAccess Tokenを取得

先ほど取得したInstallation IDを指定して、Access Tokenを取得します。

※ Installation APIの返り値の中にAccess Tokenを取得するためのURLも含まれているので、そのまま利用しています。
※ 例:https://api.github.com/app/installations/${installation_id}/access_tokens

  const resultAccessToken = await fetch(installation.access_tokens_url, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${resultJwt}`,
      accept: 'application/vnd.github+json',
      'X-GitHub-Api-Version': '2022-11-28',
    },
  });
  const accessToken = (await resultAccessToken.json());

おわりに

セキュリティ上の観点から、PAT(Personal Access Tokens)の運用からGitHub AppのAccess Tokenへの運用に切り替えているところは多いと思います(レバテックもそうですw)

思った以上に簡単にできたので、ぜひ、この記事を参考にしてみてください!

レバテック開発部

Discussion