以下のサンプルアプリの実装を見てみる。


サンプルアプリにおける GitHub App の認証方法がなんなのか確認

サンプルアプリにおける、以下の App の実装を追ってみる https://github.com/github/github-app-js-sample/blob/0c35a78328d103ffd8d4e6a568569d6c3237977b/app.js#L18-L30

// Create an authenticated Octokit client authenticated as a GitHub App
const app = new App({
  appId,
  privateKey,
  webhooks: {
    secret
  },
  ...(enterpriseHostname && {
    Octokit: Octokit.defaults({
      baseUrl: `https://${enterpriseHostname}/api/v3`
    })
  })
})

Appクラスは octokit モジュールからimport されたもの https://github.com/github/github-app-js-sample/blob/0c35a78328d103ffd8d4e6a568569d6c3237977b/app.js#L4

import { Octokit, App } from 'octokit'

octokit モジュールを見てみる。

Appクラスがexportされているのは以下。app.jsの App を exportしている。 https://github.com/octokit/octokit.js/blob/910bc2d83a823d5decb3eeef0e56f5e5e1bba361/src/index.ts#L3

export { App, OAuthApp, createNodeMiddleware } from "./app.js";

app.js の詳細も見てみる。

app.js では、@octokit/app の App を DefaultApp として import し、DefaultApp.defaults()の返り値を App として export していた https://github.com/octokit/octokit.js/blob/910bc2d83a823d5decb3eeef0e56f5e5e1bba361/src/app.ts#L1-L6

import { App as DefaultApp } from "@octokit/app";
import { OAuthApp as DefaultOAuthApp } from "@octokit/oauth-app";
 
import { Octokit } from "./octokit.js";
 
export const App = DefaultApp.defaults({ Octokit });

defaults メソッドの引数: { Octokit } はオブジェクト省略記法(ES6)により{ Octokit: Octokit }と同義

DefaultApp.defaults({ Octokit: Octokit }) の実装を確認するため、@octokit/appで export された App の defaultsメソッドを見てみる

@octokit/appから export される App の実装は以下 https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L44C1-L164

defaults メソッドの実装は以下 https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L47-L58

  static defaults<
    TDefaults extends Options,
    S extends Constructor<App<TDefaults>>,
  >(this: S, defaults: Partial<TDefaults>) {
    const AppWithDefaults = class extends this {
      constructor(...args: any[]) {
        super({
          ...defaults,
          ...args[0],
        });
      }
    };

github-app-js-sample/app.js の内容をふまえると、以下の内容(①)が App のコンストラクタに渡される

super({
  ...defaults,    // { Octokit: Octokit }
  ...args[0],     // { appId, privateKey, webhooks: { secret } }
});

App のコンストラクタは以下 https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L85-L163

  constructor(options: ConstructorOptions<TOptions>) {

コンストラクタの引数(①)が options に渡される

コンストラクタ内の処理について、認証の観点から確認。

以下の実装が関係してきそう

https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L85-L111

  constructor(options: ConstructorOptions<TOptions>) {
    const Octokit = (options.Octokit ||
      OctokitCore) as OctokitClassType<TOptions>;
 
    const authOptions = Object.assign(
      {
        appId: options.appId,
        privateKey: options.privateKey,
      },
      options.oauth
        ? {
            clientId: options.oauth.clientId,
            clientSecret: options.oauth.clientSecret,
          }
        : {},
    );
 
    const octokitOptions: OctokitOptions = {
      authStrategy: createAppAuth,
      auth: authOptions,
    };
 
    if ("log" in options && typeof options.log !== "undefined") {
      octokitOptions.log = options.log;
    }
 
    this.octokit = new Octokit(octokitOptions) as OctokitType<TOptions>;

変数: authOptionsにoptionsの内容をassign コンストラクタの引数(①)のappId, privateKeyなどがassign

OctokitOptions タイプの変数: octokitOptions に以下が設定される authStrategy プロパティにcreateAppAuthを設定 auth プロパティに authOptions 変数を設定 変数: octokitOptions をOctokitクラスのコンストラクタに渡し、インスタンス化してthis.octokitに格納

Octokitクラスのコンストラクタを確認。 Octokit クラスは@octokit/coreからimportされている https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L1C62-L1C76

import { Octokit as OctokitCore, type OctokitOptions } from "@octokit/core";

Octokitクラスの実装。 https://github.com/octokit/core.js/blob/main/src/index.ts

Octokitクラスのコンストラクトは OctokitOptions タイプのオブジェクトを受け取り、options 変数に格納される https://github.com/octokit/core.js/blob/b1b81171507fa4a025e08bc5f5d84cf90572c2c2/src/index.ts#L109-L125

  constructor(options: OctokitOptions = {}) {

コンストラクト内では、options の内容をもとに行われる処理についてコメントで説明されている https://github.com/octokit/core.js/blob/b1b81171507fa4a025e08bc5f5d84cf90572c2c2/src/index.ts#L149-L188

    // (1) If neither `options.authStrategy` nor `options.auth` are set, the `octokit` instance
    //     is unauthenticated. The `this.auth()` method is a no-op and no request hook is registered.
    // (2) If only `options.auth` is set, use the default token authentication strategy.
    // (3) If `options.authStrategy` is set then use it and pass in `options.auth`. Always pass own request as many strategies accept a custom request instance.
    // TODO: type `options.auth` based on `options.authStrategy`.
    if (!options.authStrategy) {
      if (!options.auth) {
        // (1)
        this.auth = async () => ({
          type: "unauthenticated",
        });
      } else {
        // (2)
        const auth = createTokenAuth(options.auth as string);
        // @ts-ignore  ¯\_(ツ)_/¯
        hook.wrap("request", auth.hook);
        this.auth = auth;
      }
    } else {
      const { authStrategy, ...otherOptions } = options;
      const auth = authStrategy(
        Object.assign(
          {
            request: this.request,
            log: this.log,
            // we pass the current octokit instance as well as its constructor options
            // to allow for authentication strategies that return a new octokit instance
            // that shares the same internal state as the current one. The original
            // requirement for this was the "event-octokit" authentication strategy
            // of https://github.com/probot/octokit-auth-probot.
            octokit: this,
            octokitOptions: otherOptions,
          },
          options.auth,
        ),
      );
      // @ts-ignore  ¯\_(ツ)_/¯
      hook.wrap("request", auth.hook);
      this.auth = auth;
    }

コメント部分 - //(1) options.AuthStrategyoptions.auth のどちらも設定されていない場合、octokitインスタンスは認証されません。this.auth () メソッドは何もしませんし、リクエストフックも登録されていません。 - //(2) options.authだけが設定されている場合は、デフォルトのトークン認証方法を使用してください。 - //(3)「Options.AuthStrategy」が設定されている場合は、それを使用して「options.auth」を渡してください。多くのストラテジーはカスタムリクエストインスタンスを受け入れるので、常に自分のリクエストを渡してください。

authStrategy には createAppAuth が渡されていたので、154行目のif (!options.authStrategy) {には入らず、167行目のelseに入りそう

167行目のelse中では、分割代入によりauthStrategyメソッドとotherOptios に分けられ、authStrategyメソッドが実行されそう https://github.com/octokit/core.js/blob/b1b81171507fa4a025e08bc5f5d84cf90572c2c2/src/index.ts#L168-L185

      const { authStrategy, ...otherOptions } = options;
      const auth = authStrategy(
        Object.assign(
          {
            request: this.request,
            log: this.log,
            // we pass the current octokit instance as well as its constructor options
            // to allow for authentication strategies that return a new octokit instance
            // that shares the same internal state as the current one. The original
            // requirement for this was the "event-octokit" authentication strategy
            // of https://github.com/probot/octokit-auth-probot.
            octokit: this,
            octokitOptions: otherOptions,
          },
          options.auth,
        ),
      );
      // @ts-ignore  ¯\_(ツ)_/¯

authStrategyメソッドには options.authが渡されそう これは遡るとgithub-app-js-sample/app.jsのAppコンストラクトに渡されていた以下の内容に相当 https://github.com/github/github-app-js-sample/blob/0c35a78328d103ffd8d4e6a568569d6c3237977b/app.js#L19-L24

const app = new App({
  appId,
  privateKey,
  webhooks: {
    secret
  },

つまり、authStrategyメソッドに対して、上記のようなappId, privateKey, webhooksが渡されることになる。

ここでの authStrategy とは?

authStrategy には createAppAuth が渡されていた。

認証の方法はcreateAppAuthで決定されそう。ここの詳細を追ってみる

createAppAuthは@octokit/auth-appからimprtされてきたもの https://github.com/octokit/app.js/blob/5bb92eeb59cf9240475ecc811480559ca202347f/src/index.ts#L2C32-L2C49

import { createAppAuth } from "@octokit/auth-app";

createAppAuthの詳細を見てみる https://github.com/octokit/auth-app.js/blob/4486c10028249f4f2ffaabeafde986edca92e7b5/src/index.ts#L30C17-L30C30

export function createAppAuth(options: StrategyOptions): AuthInterface {

createAppAuth はメソッド

また、利用する認証方法ごとに createAppAuth メソッドのプロパティをどう指定すれば良いかについてREADME.mdで説明されている。 https://github.com/octokit/auth-app.js/?tab=readme-ov-file#standalone-usage


結局よくわからず