[DOCS]: How to get an installation access token
frank-zsy opened this issue · 7 comments
Describe the need
In the former version of app.js
, I can use app.getInstallationAccessToken({ installationId })
to get an installation access token of a GitHub Apps to perform further actions like auth a GraphQL client. But in the latest version of this library, I can not find a method to get an installation token now. Could you please give me an example or add related code to the documentation?
SDK Version
octokit/app.js v13.1.1
API Version
latest
Relevant log output
No response
Code of Conduct
- I agree to follow this project's Code of Conduct
In the former version of app.js, I can use app.getInstallationAccessToken({ installationId }) to get an installation access token of a GitHub Apps to perform further actions like auth a GraphQL client
I think another implication of this being inaccessible is that it means you can't use the access token to create a custom Octokit client that uses plug-ins like "@octokit/plugin-throttling"
(although maybe there is a way and I'm just not aware?)
There is always the app.getInstallationOctokit
that you can use to create an Octokit client for an installation
Starting with v10 of this package, it was repurposed and the method you are looking for has been moved to the @octokit/auth-app
package, see #74
@wolfy1339 I think I'm missing something.
Looking at the "@octokit/auth-app"
docs section titled "Authenticate as installation" I see:
const auth = createAppAuth({
appId: 1,
privateKey: "-----BEGIN PRIVATE KEY-----\n...",
clientId: "lv1.1234567890abcdef",
clientSecret: "1234567890abcdef12341234567890abcdef1234",
});
// Retrieve installation access token
const installationAuthentication = await auth({
type: "installation",
installationId: 123,
});
But I'm not sure how to get the installation ID. (That's why I was commenting on here to begin with.)
The only way I knew of to get that installation id was using @octokit/app
:
import { App } from "@octokit/app";
const app = new App({ appId, privateKey: pem });
// First we need to get the installation id for the repo
const { data: installation } = await app.octokit.request(
`GET /repos/${organization}/${repository}/installation`
);
Any pointers?
I guess I can use @octokit/app
first to fetch the installation id, and then use @octokit/auth-app
so I can also use plugins like @octokit/plugin-throttling
.
async function getInstallationId() {
const app = new App({ appId, privateKey });
// First we need to get the installation id for the repo
const { data: installation } = await app.octokit.request(
`GET /repos/${organization}/${repository}/installation`
);
return installation.id;
}
const installationId = await getInstallationId();
const ThrottledOctokit = Octokit.plugin(throttling);
const octokit = new ThrottledOctokit({
auth: {
appId,
privateKey,
installationId,
},
authStrategy: createAppAuth,
throttle: { ... },
});
To get the token you can do this
const octokit = await app.getInstallationOctokit(installationId);
const { token } = await octokit.auth({ type: "installation" })
Unfortunately we don't have a helper method to get an octokit instance based on an owner or a repository, but you can use one of these endpoints
- https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-an-organization-installation-for-the-authenticated-app
- https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
- https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-a-user-installation-for-the-authenticated-app
For example
const { data: installation } = await app.octokit.request("GET /repos/{owner}/{repo}/installation, { owner, repo })
Does that work for you?
I ended up doing more or less what I commented above.
import { App } from "@octokit/app";
import { createAppAuth } from "@octokit/auth-app";
import { throttling } from "@octokit/plugin-throttling";
import { Octokit } from "@octokit/rest";
import dotenv from "dotenv";
dotenv.config({ path: "./.env.local" });
const privateKey = process.env.PEM;
const appId = process.env.APP_ID;
const organization = process.env.ORGANIZATION;
const repository = process.env.REPOSITORY;
export async function getOctokit() {
const installationId = await getInstallationId();
const ThrottledOctokit = Octokit.plugin(throttling);
const octokit = new ThrottledOctokit({
auth: {
appId,
privateKey,
installationId,
},
authStrategy: createAppAuth,
throttle: {
onRateLimit: (retryAfter, options, octokit, retryCount) => {
octokit.log.warn(
`Request quota exhausted for request ${options.method} ${options.url}`
);
if (retryCount < 2) {
octokit.log.info(`Retrying after ${retryAfter} seconds!`);
return true;
}
},
onSecondaryRateLimit: (retryAfter, options, octokit) => {
octokit.log.warn(
`SecondaryRateLimit detected for request ${options.method} ${options.url}`
);
},
},
});
return octokit;
}
async function getInstallationId() {
const app = new App({ appId, privateKey });
// First we need to get the installation id for the repo
const { data: installation } = await app.octokit.request(
`GET /repos/${organization}/${repository}/installation`
);
return installation.id;
}
Here is a simpler version that does the same thing. We recommend to use octokit
over @octokit/rest
.
import { App, Octokit } from "octokit";
import dotenv from "dotenv";
dotenv.config({ path: "./.env.local" });
const privateKey = process.env.PEM;
const appId = process.env.APP_ID;
const owner = process.env.ORGANIZATION;
const repo = process.env.REPOSITORY;
export async function getOctokit() {
const app = new App({ appId, privateKey });
// https://docs.github.com/en/rest/apps/apps?#get-a-repository-installation-for-the-authenticated-app
const { data: installation } = await app.octokit.request(
`GET /repos/{owner}/{repo}/installation`,
{ owner, repo }
);
return app.getInstallationOctokit(installation.id)
}
I think we answered the original question so I'm going to close the issue, but please feel free to ask follow up questions.