0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Google Apps ScriptでGitHub Appsの認証をする

Posted at

はじめに

Google Apps Script(GAS)でGitHub Appsの認証をする方法について説明します。

だいぶ前にやったことなんですが、役に立つ人がいるかもしれないのでメモとして残しておきます。

準備

GitHub Appsの設定画面でpemファイルをダウンロードして、 openssl pkey -in pemファイル の出力をGASのユーザープロパティとかスクリプトプロパティとかに設定しておく1

コード

少し長いのですが、GitHub Appsの認証を行う関数です。

function getAccessToken() {
  const props = PropertiesService.getUserProperties();
  const token = props.getProperty('token');

  // プロパティが存在しなかったら new Date(null) になって1970/1/1 9:00になる
  const expiration = new Date(props.getProperty('expiration'));

  if (token !== null && new Date().valueOf() < expiration.valueOf()) {
    return token;
  }

  const privateKey = props.getProperty('privateKey');

  const header = { alg: 'RS256', typ: 'JWT' };
  const payload = {
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 5 * 60,
    iss: 0 /* App IDを入れる */,
  };

  const toSign = Utilities.base64EncodeWebSafe(JSON.stringify(header)) + '.' + Utilities.base64EncodeWebSafe(JSON.stringify(payload)).replace(/=+$/, '');
  const signatureBytes = Utilities.computeRsaSha256Signature(toSign, privateKey);
  const signature = Utilities.base64EncodeWebSafe(signatureBytes).replace(/=+$/, '');

  const jwt = `${toSign}.${signature}`;

  const installationsResponse = UrlFetchApp.fetch('https://api.github.com/app/installations', {
    method: 'get',
    headers: {
      accept: 'application/vnd.github.machine-man-preview+json',
      authorization: `Bearer ${jwt}`,
    },
  });
  const installations = JSON.parse(installationsResponse.getContentText());
  const installationId = installations.find(v => v.account.login === 'XXX' /* 適当な条件で判定する */).id;

  const accessTokenResponse = UrlFetchApp.fetch(
    `https://api.github.com/app/installations/${installationId}/access_tokens`, {
    method: 'post',
    headers: {
      accept: 'application/vnd.github.machine-man-preview+json',
      authorization: `Bearer ${jwt}`,
    },
  });
  const accessTokenJson = JSON.parse(accessTokenResponse.getContentText());
  const accessToken = accessTokenJson.token;

  props.setProperties({
    expiration: accessTokenJson.expires_at,
    token: accessToken,
  });

  return accessToken;
}

この関数は

  • アクセストークンを1度も取得したことがなかったらアクセストークンを取得して返す
  • アクセストークンが取得済みで、期限が切れていなかったらそのトークンを返す
  • アクセストークンが取得済みで、期限が切れていたら、アクセストークンを取得し直して返す

というのをしているので、アクセストークンが欲しい場面で毎回この関数を呼ぶようにするといい感じになります。こんな感じです。

UrlFetchApp.fetch('https://api.github.com/graphql', {
  method: 'post',
  contentType: 'application/json',
  headers: {
    Authorization: `Bearer ${getAccessToken()}`,
  },
  payload: ...
});

どういう流れでアクセストークンを取得しているのかは、調べると出てくると思うので省略します。

  1. 他の人から見えない置き方をしていればなんでもいいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?