octkitを利用せずにGitHub AppからAccess Tokenを取得する - TypeScript編 -
TL;DR
- TypeScriptを使ってGitHub AppからAccess Tokenを取得する方法をまとめました
- GitHubの公式が提供しているGitHub APIのラッパー(octkit)は利用しません
- GitHub Appの作成方法などは参考記事を参照してください
参考記事
以下の神資料が一番わかりやすいので、参考にしてください(めちゃくちゃ助かりました🥹)
なぜ、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の取得
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の作成
公式のドキュメントか紹介した参考記事を参照してください。
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)
思った以上に簡単にできたので、ぜひ、この記事を参考にしてみてください!
レバテック開発部の公式テックブログです! レバテック開発部 Advent Calendar 2024 実施中: qiita.com/advent-calendar/2024/levtech
Discussion