Skip to content

Latest commit

 

History

History
80 lines (59 loc) · 2.8 KB

github-access-tokens.md

File metadata and controls

80 lines (59 loc) · 2.8 KB

Explanation for how we use GitHub access tokens with Probot

Many of the applications in this repository use the Probot framework to power GitHub apps. In the source code of some of these apps (e.g., bundle-size) you will notice that we define an environment variable called GITHUB_ACCESS_TOKEN, which should be set to a personal access token generated by the user:

# .env

# A GitHub user access token that can read team members
ACCESS_TOKEN=0123456789abcdef0123456789abcdef01234567

An experienced GitHub Apps/Probot developer would wonder why this is necessary, as GitHub Apps have their own way to authenticate themselves with the GitHub API, using the App ID and its private key, which we also provide as environment variables:

# .env

# The ID of your GitHub App
APP_ID=12345
# Base64 encoded private key from GitHub
PRIVATE_KEY=0123456789abcdefghijklmnopqrstuvwxyz

In fact, we use both approaches!

Inside Probot Webhook handlers, the context object has a github field that is an Octokit instance that's already authenticated to perform API calls with the permissions given to the app:

// app.js

module.exports = app => {
  app.on('pull_request.opened', async context => {
    const check = await context.github.checks.create(params);
    context.log(`Created check:`, check);
  };
};

Whereas in other contexts we construct an Octokit instance using the personal access token:

// app.js

module.exports = app => {
  const userBasedGithub = new Octokit({
    authStrategy: createTokenAuth,
    auth: process.env.ACCESS_TOKEN,
  });

  app.on('pull_request.opened', /* ... */);

  app.on('pull_request_review.submitted', async context => {
    const approver = context.payload.review.user.login;

    // NOTE: this doesn't use `context.github`!
    const allowedApprovers = await userBasedGithub.teams
    .listMembers({team_id: 1234})
    .then(result => result.data.map(user => user.login));

    const isAllowedApprover = allowedApprovers.includes(approver);
    context.log(`Approving user ${approver} is allowed:`, isAllowedApprover);
  });
};

So why the duality?

Unfortunately, the GitHub API permission scopes are confusing and not always in line with the documentation.

There is currently no way, for example, to get read-only access to organization teams and their members as a GitHub App (only full administration permissions can be given to an app), but it is possible using a personal access token of a member of the organization, if that access token was given the read:org permission.

Contrary, it is not currently possible to assign a reviewer to a pull request with a personal access token, but it is possible to do so with an app that was given the appropriate pull requests permission.