Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

@octokit/app

Package Overview
Dependencies
Maintainers
2
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@octokit/app - npm Package Compare versions

Comparing version 4.3.0 to 10.0.0-beta.1

dist-src/each-installation.js

479

dist-node/index.js

@@ -5,88 +5,423 @@ 'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var core = require('@octokit/core');
var authApp = require('@octokit/auth-app');
var oauthApp = require('@octokit/oauth-app');
var webhooks$1 = require('@octokit/webhooks');
var pluginPaginateRest = require('@octokit/plugin-paginate-rest');
var request = require('@octokit/request');
var LRU = _interopDefault(require('lru-cache'));
var jsonwebtoken = _interopDefault(require('jsonwebtoken'));
function _asyncIterator(iterable) {
var method;
// https://github.com/isaacs/node-lru-cache#readme
function getCache() {
return new LRU({
// cache max. 15000 tokens, that will use less than 10mb memory
max: 15000,
// Cache for 59 minutes (1 minute less than GitHub expiry)
maxAge: 1000 * 60 * 59
});
if (typeof Symbol !== "undefined") {
if (Symbol.asyncIterator) {
method = iterable[Symbol.asyncIterator];
if (method != null) return method.call(iterable);
}
if (Symbol.iterator) {
method = iterable[Symbol.iterator];
if (method != null) return method.call(iterable);
}
}
throw new TypeError("Object is not async iterable");
}
function getSignedJsonWebToken({
id,
privateKey
}) {
const now = Math.floor(Date.now() / 1000);
const payload = {
iat: now,
exp: now + 60 * 10 - 30,
iss: id
function _AwaitValue(value) {
this.wrapped = value;
}
function _AsyncGenerator(gen) {
var front, back;
function send(key, arg) {
return new Promise(function (resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null
};
if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}
function resume(key, arg) {
try {
var result = gen[key](arg);
var value = result.value;
var wrappedAwait = value instanceof _AwaitValue;
Promise.resolve(wrappedAwait ? value.wrapped : value).then(function (arg) {
if (wrappedAwait) {
resume(key === "return" ? "return" : "next", arg);
return;
}
settle(result.done ? "return" : "normal", arg);
}, function (err) {
resume("throw", err);
});
} catch (err) {
settle("throw", err);
}
}
function settle(type, value) {
switch (type) {
case "return":
front.resolve({
value: value,
done: true
});
break;
case "throw":
front.reject(value);
break;
default:
front.resolve({
value: value,
done: false
});
break;
}
front = front.next;
if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}
this._invoke = send;
if (typeof gen.return !== "function") {
this.return = undefined;
}
}
if (typeof Symbol === "function" && Symbol.asyncIterator) {
_AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
return this;
};
const token = jsonwebtoken.sign(payload, privateKey, {
algorithm: "RS256"
}
_AsyncGenerator.prototype.next = function (arg) {
return this._invoke("next", arg);
};
_AsyncGenerator.prototype.throw = function (arg) {
return this._invoke("throw", arg);
};
_AsyncGenerator.prototype.return = function (arg) {
return this._invoke("return", arg);
};
function _wrapAsyncGenerator(fn) {
return function () {
return new _AsyncGenerator(fn.apply(this, arguments));
};
}
function _awaitAsyncGenerator(value) {
return new _AwaitValue(value);
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
const VERSION = "10.0.0-beta.1";
function webhooks(appOctokit, options) {
return new webhooks$1.Webhooks({
secret: options.secret,
path: "/api/github/webhooks",
transform: async event => {
const octokit = await appOctokit.auth({
type: "installation",
installationId: event.payload.installation.id,
factory: auth => {
return new auth.octokit.constructor(_objectSpread2(_objectSpread2({}, auth.octokitOptions), {}, {
authStrategy: authApp.createAppAuth
}, {
auth: _objectSpread2(_objectSpread2({}, auth), {}, {
installationId: event.payload.installation.id
})
}));
}
});
return _objectSpread2(_objectSpread2({}, event), {}, {
octokit: octokit
});
}
});
return token;
}
function getInstallationAccessToken(state, {
installationId,
repositoryIds,
permissions
}) {
const token = state.cache.get(installationId);
async function getInstallationOctokit(app, installationId) {
return app.octokit.auth({
type: "installation",
installationId: installationId,
if (token) {
return Promise.resolve(token);
factory(auth) {
const options = _objectSpread2(_objectSpread2({}, auth.octokitOptions), {}, {
authStrategy: authApp.createAppAuth
}, {
auth: _objectSpread2(_objectSpread2({}, auth), {}, {
installationId: installationId
})
});
return new auth.octokit.constructor(options);
}
});
}
function eachInstallationFactory(app) {
return Object.assign(eachInstallation.bind(null, app), {
iterator: eachInstallationIterator.bind(null, app)
});
}
async function eachInstallation(app, callback) {
const i = eachInstallationIterator(app)[Symbol.asyncIterator]();
let result = await i.next();
while (!result.done) {
await callback(result.value);
result = await i.next();
}
}
function eachInstallationIterator(app) {
return {
[Symbol.asyncIterator]() {
return _wrapAsyncGenerator(function* () {
const iterator = pluginPaginateRest.composePaginateRest.iterator(app.octokit, "GET /app/installations");
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
return state.request({
method: "POST",
url: "/app/installations/:installation_id/access_tokens",
installation_id: installationId,
headers: {
accept: "application/vnd.github.machine-man-preview+json",
// TODO: cache the installation token if it's been less than 60 minutes
authorization: `bearer ${getSignedJsonWebToken(state)}`
},
repository_ids: repositoryIds,
permissions
}).then(response => {
state.cache.set(installationId, response.data.token);
return response.data.token;
var _iteratorError;
try {
for (var _iterator = _asyncIterator(iterator), _step, _value; _step = yield _awaitAsyncGenerator(_iterator.next()), _iteratorNormalCompletion = _step.done, _value = yield _awaitAsyncGenerator(_step.value), !_iteratorNormalCompletion; _iteratorNormalCompletion = true) {
const {
data: installations
} = _value;
for (const installation of installations) {
const installationOctokit = yield _awaitAsyncGenerator(getInstallationOctokit(app, installation.id));
yield {
octokit: installationOctokit,
installation
};
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
yield _awaitAsyncGenerator(_iterator.return());
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
})();
}
};
}
function eachRepositoryFactory(app) {
return Object.assign(eachRepository.bind(null, app), {
iterator: eachRepositoryIterator.bind(null, app)
});
}
async function eachRepository(app, callback) {
const i = eachRepositoryIterator(app)[Symbol.asyncIterator]();
let result = await i.next();
const VERSION = "4.3.0";
while (!result.done) {
await callback(result.value);
result = await i.next();
}
}
function eachRepositoryIterator(app) {
return {
[Symbol.asyncIterator]() {
return _wrapAsyncGenerator(function* () {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
let deprecateOnce = () => {
console.warn("[@octokit/app] Deprecated. Use @octokit/app-auth instead. See https://github.com/octokit/app.js/#deprecated");
var _iteratorError;
deprecateOnce = () => {};
};
try {
for (var _iterator = _asyncIterator(app.eachInstallation.iterator()), _step, _value; _step = yield _awaitAsyncGenerator(_iterator.next()), _iteratorNormalCompletion = _step.done, _value = yield _awaitAsyncGenerator(_step.value), !_iteratorNormalCompletion; _iteratorNormalCompletion = true) {
const {
octokit
} = _value;
const repositoriesIterator = pluginPaginateRest.composePaginateRest.iterator(octokit, "GET /installation/repositories");
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2;
try {
for (var _iterator2 = _asyncIterator(repositoriesIterator), _step2, _value2; _step2 = yield _awaitAsyncGenerator(_iterator2.next()), _iteratorNormalCompletion2 = _step2.done, _value2 = yield _awaitAsyncGenerator(_step2.value), !_iteratorNormalCompletion2; _iteratorNormalCompletion2 = true) {
const {
data: repositories
} = _value2;
for (const repository of repositories) {
yield {
octokit: octokit,
repository
};
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
yield _awaitAsyncGenerator(_iterator2.return());
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
yield _awaitAsyncGenerator(_iterator.return());
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
})();
}
};
}
class App {
constructor({
id,
privateKey,
baseUrl,
cache
}) {
const state = {
id,
privateKey,
request: baseUrl ? request.request.defaults({
baseUrl
}) : request.request,
cache: cache || getCache()
};
this.getSignedJsonWebToken = getSignedJsonWebToken.bind(null, state);
this.getInstallationAccessToken = getInstallationAccessToken.bind(null, state);
deprecateOnce();
constructor(options) {
const Octokit = options.Octokit || core.Octokit;
const authOptions = Object.assign({
appId: options.appId,
privateKey: options.privateKey
}, options.oauth ? {
clientId: options.oauth.clientId,
clientSecret: options.oauth.clientSecret
} : {});
this.octokit = new Octokit({
authStrategy: authApp.createAppAuth,
auth: authOptions,
log: options.log
});
this.log = Object.assign({
debug: () => {},
info: () => {},
warn: console.warn.bind(console),
error: console.error.bind(console)
}, options.log); // set app.webhooks depending on whether "webhooks" option has been passed
if (options.webhooks) {
this.webhooks = webhooks(this.octokit, options.webhooks);
} else {
Object.defineProperty(this, "webhooks", {
get() {
throw new Error("[@octokit/app] webhooks option not set");
}
});
} // set app.oauth depending on whether "oauth" option has been passed
if (options.oauth) {
this.oauth = new oauthApp.OAuthApp(_objectSpread2(_objectSpread2({}, options.oauth), {}, {
Octokit
}));
} else {
Object.defineProperty(this, "oauth", {
get() {
throw new Error("[@octokit/app] oauth.clientId / oauth.clientSecret options are not set");
}
});
}
this.getInstallationOctokit = getInstallationOctokit.bind(null, this);
this.eachInstallation = eachInstallationFactory(this);
this.eachRepository = eachRepositoryFactory(this);
}

@@ -96,4 +431,12 @@

App.VERSION = VERSION;
function getNodeMiddleware(app) {
return oauthApp.getNodeMiddleware(app.oauth, {
onUnhandledRequest: (request, response) => {
return app.webhooks.middleware(request, response);
}
});
}
exports.App = App;
exports.getNodeMiddleware = getNodeMiddleware;
//# sourceMappingURL=index.js.map

82

dist-src/index.js

@@ -1,23 +0,69 @@

import { request } from "@octokit/request";
import { getCache } from "./get-cache";
import { getInstallationAccessToken } from "./get-installation-access-token";
import { getSignedJsonWebToken } from "./get-signed-json-web-token";
import { Octokit as OctokitCore } from "@octokit/core";
import { createAppAuth } from "@octokit/auth-app";
import { OAuthApp, getNodeMiddleware as oauthNodeMiddleware, } from "@octokit/oauth-app";
import { VERSION } from "./version";
let deprecateOnce = () => {
console.warn("[@octokit/app] Deprecated. Use @octokit/app-auth instead. See https://github.com/octokit/app.js/#deprecated");
deprecateOnce = () => { };
};
import { webhooks } from "./webhooks";
import { eachInstallationFactory } from "./each-installation";
import { eachRepositoryFactory } from "./each-repository";
import { getInstallationOctokit } from "./get-installation-octokit";
export class App {
constructor({ id, privateKey, baseUrl, cache }) {
const state = {
id,
privateKey,
request: baseUrl ? request.defaults({ baseUrl }) : request,
cache: cache || getCache(),
};
this.getSignedJsonWebToken = getSignedJsonWebToken.bind(null, state);
this.getInstallationAccessToken = getInstallationAccessToken.bind(null, state);
deprecateOnce();
constructor(options) {
const Octokit = options.Octokit || OctokitCore;
const authOptions = Object.assign({
appId: options.appId,
privateKey: options.privateKey,
}, options.oauth
? {
clientId: options.oauth.clientId,
clientSecret: options.oauth.clientSecret,
}
: {});
this.octokit = new Octokit({
authStrategy: createAppAuth,
auth: authOptions,
log: options.log,
});
this.log = Object.assign({
debug: () => { },
info: () => { },
warn: console.warn.bind(console),
error: console.error.bind(console),
}, options.log);
// set app.webhooks depending on whether "webhooks" option has been passed
if (options.webhooks) {
this.webhooks = webhooks(this.octokit, options.webhooks);
}
else {
Object.defineProperty(this, "webhooks", {
get() {
throw new Error("[@octokit/app] webhooks option not set");
},
});
}
// set app.oauth depending on whether "oauth" option has been passed
if (options.oauth) {
this.oauth = new OAuthApp({
...options.oauth,
Octokit,
});
}
else {
Object.defineProperty(this, "oauth", {
get() {
throw new Error("[@octokit/app] oauth.clientId / oauth.clientSecret options are not set");
},
});
}
this.getInstallationOctokit = getInstallationOctokit.bind(null, this);
this.eachInstallation = eachInstallationFactory(this);
this.eachRepository = eachRepositoryFactory(this);
}
}
App.VERSION = VERSION;
export function getNodeMiddleware(app) {
return oauthNodeMiddleware(app.oauth, {
onUnhandledRequest: (request, response) => {
return app.webhooks.middleware(request, response);
},
});
}

@@ -1,1 +0,1 @@

export const VERSION = "4.3.0";
export const VERSION = "10.0.0-beta.1";

@@ -1,13 +0,23 @@

import { AppOptions, InstallationAccessTokenOptions } from "./types";
export declare class App {
/// <reference types="node" />
import { Octokit as OctokitCore } from "@octokit/core";
import { OAuthApp } from "@octokit/oauth-app";
import { Options, EachInstallationInterface, EachRepositoryInterface, GetInstallationOctokitInterface } from "./types";
import { webhooks } from "./webhooks";
export declare class App<O extends Options = Options> {
static VERSION: string;
constructor({ id, privateKey, baseUrl, cache }: AppOptions);
/**
* In order to authenticate as a GitHub App, you need to generate a Private Key and use it to sign a JSON Web Token (jwt) and encode it. See also the [GitHub Developer Docs](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/).
*/
getSignedJsonWebToken: () => string;
/**
* Once you have authenticated as a GitHub App, you can use that in order to request an installation access token. Calling `requestToken()` automatically performs the app authentication for you. See also the [GitHub Developer Docs](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-an-installation).
*/
getInstallationAccessToken: (options: InstallationAccessTokenOptions) => Promise<string>;
octokit: OctokitCore;
webhooks: ReturnType<typeof webhooks>;
oauth: OAuthApp;
getInstallationOctokit: GetInstallationOctokitInterface;
eachInstallation: EachInstallationInterface;
eachRepository: EachRepositoryInterface;
log: {
debug: (message: string, additionalInfo?: object) => void;
info: (message: string, additionalInfo?: object) => void;
warn: (message: string, additionalInfo?: object) => void;
error: (message: string, additionalInfo?: object) => void;
[key: string]: unknown;
};
constructor(options: O);
}
export declare function getNodeMiddleware(app: App): (request: import("http").IncomingMessage, response: import("http").ServerResponse) => Promise<void>;

@@ -1,77 +0,42 @@

import LRUCache from "lru-cache";
import { request } from "@octokit/request";
export interface State {
id: number;
import { Octokit } from "@octokit/core";
import { Endpoints } from "@octokit/types";
export declare type Options = {
appId: number | string;
privateKey: string;
request: typeof request;
cache: LRUCache<number, string> | {
get: (key: number) => string;
set: (key: number, value: string) => any;
webhooks?: {
secret: string;
};
}
export interface AppOptions {
/**
* App ID. Can be found in the app’s settings
*/
id: number;
/**
* Content of the app’s *.pem file. Can be created in the app’s settings
*/
privateKey: string;
/**
* Set `baseUrl` for use with GitHub enterprise.
*
* @example `'https://github-enterprise.com/api/v3'`
*/
baseUrl?: string;
/**
* Installation tokens expire after an hour. By default, `@octokit/app` is caching up to 15000 tokens simultaneously using [`lru-cache`](https://github.com/isaacs/node-lru-cache). You can pass your own cache implementation by passing `options.cache.{get,set}` to the constructor.
*/
cache?: LRUCache<number, string> | {
get: (key: number) => string;
set: (key: number, value: string) => any;
oauth?: {
clientId: string;
clientSecret: string;
};
Octokit?: typeof Octokit;
log?: {
debug: (message: string) => unknown;
info: (message: string) => unknown;
warn: (message: string) => unknown;
error: (message: string) => unknown;
};
};
export declare type InstallationFunctionOptions = {
octokit: Octokit;
installation: Endpoints["GET /app/installations"]["response"]["data"][0];
};
export declare type EachInstallationFunction = (options: InstallationFunctionOptions) => unknown | Promise<unknown>;
export interface EachInstallationInterface {
(callback: EachInstallationFunction): Promise<void>;
iterator: () => AsyncIterable<InstallationFunctionOptions>;
}
export declare type Read = "none" | "read";
export declare type ReadWrite = Read | "write";
export declare type ReadWriteAdmin = ReadWrite | "admin";
export declare type InstallationAccessTokenPermissions = {
administration?: ReadWrite;
blocking?: ReadWrite;
checks?: ReadWrite;
content_references?: ReadWrite;
contents?: ReadWrite;
deployments?: ReadWrite;
emails?: ReadWrite;
followers?: ReadWrite;
gpg_keys?: ReadWrite;
issues?: ReadWrite;
keys?: ReadWrite;
members?: ReadWrite;
organization_administration?: ReadWrite;
organization_hooks?: ReadWrite;
organization_plan?: Read;
organization_projects?: ReadWriteAdmin;
organization_user_blocking?: ReadWrite;
packages?: ReadWrite;
pages?: ReadWrite;
plan?: Read;
pull_requests?: ReadWrite;
repository_hooks?: ReadWrite;
repository_metadata?: Read;
repository_projects?: ReadWriteAdmin;
single_file?: ReadWrite;
starring?: ReadWrite;
statuses?: ReadWrite;
team_discussions?: ReadWrite;
vulnerability_alerts?: Read;
watching?: ReadWrite;
declare type EachRepositoryFunctionOptions = {
octokit: Octokit;
repository: Endpoints["GET /installation/repositories"]["response"]["data"]["repositories"][0];
};
export declare type InstallationAccessTokenOptions = {
/**
* Find the app’s installation token at https://github.com/apps/<app name>/installations/new. Select the account then copy the number from the end of the URL
*/
installationId: number;
repositoryIds?: number[];
permissions?: InstallationAccessTokenPermissions;
};
export declare type EachRepositoryFunction = (options: EachRepositoryFunctionOptions) => unknown | Promise<unknown>;
export interface EachRepositoryInterface {
(callback: EachRepositoryFunction): Promise<void>;
iterator: () => AsyncIterable<EachRepositoryFunctionOptions>;
}
export interface GetInstallationOctokitInterface {
(installationId: number): Promise<Octokit>;
}
export {};

@@ -1,1 +0,1 @@

export declare const VERSION = "4.3.0";
export declare const VERSION = "10.0.0-beta.1";
{
"name": "@octokit/app",
"description": "GitHub Apps toolset for Node.js",
"version": "4.3.0",
"version": "10.0.0-beta.1",
"license": "MIT",

@@ -12,17 +12,10 @@ "files": [

"sideEffects": false,
"homepage": "https://github.com/octokit/app.js#readme",
"bugs": {
"url": "https://github.com/octokit/app.js/issues"
},
"contributors": [
{
"name": "Gregor Martynus",
"url": "https://github.com/gr2m"
}
],
"repository": "https://github.com/octokit/app.js",
"dependencies": {
"@octokit/request": "^5.0.0",
"jsonwebtoken": "^8.3.0",
"lru-cache": "^6.0.0"
"@octokit/auth-app": "^2.10.0",
"@octokit/core": "^3.2.0",
"@octokit/oauth-app": "^2.0.1",
"@octokit/plugin-paginate-rest": "^2.6.0",
"@octokit/types": "^5.5.0",
"@octokit/webhooks": "^7.15.1"
},

@@ -34,15 +27,10 @@ "devDependencies": {

"@types/jest": "^26.0.0",
"@types/jsonwebtoken": "^8.3.0",
"@types/lolex": "^5.1.0",
"@types/lru-cache": "^5.1.0",
"@types/nock": "^11.1.0",
"@types/simple-mock": "^0.8.1",
"jest": "^25.1.0",
"lolex": "^6.0.0",
"nock": "^13.0.0",
"@types/node": "^14.14.6",
"fetch-mock": "^9.10.7",
"jest": "^26.6.1",
"mockdate": "^3.0.2",
"prettier": "^2.0.0",
"semantic-release": "^17.0.0",
"semantic-release-plugin-update-version-in-files": "^1.0.0",
"simple-mock": "^0.8.0",
"ts-jest": "^25.3.0",
"ts-jest": "^26.4.3",
"typescript": "^3.4.5"

@@ -49,0 +37,0 @@ },

@@ -1,18 +0,28 @@

<a name="deprecated"></a>
# app.js
# ⚠️ Deprecated
> GitHub App toolset for Node.js
`@octokit/app` is being deprecated in favor of [`@octokit/auth-app`](https://github.com/octokit/auth-app.js/#readme). The `@octokit/app` package will be repurposed, starting with version 10.0.0.
[![@latest](https://img.shields.io/npm/v/@octokit/app.svg)](https://www.npmjs.com/package/@octokit/app)
[![Build Status](https://github.com/octokit/app.js/workflows/Test/badge.svg)](https://github.com/octokit/app.js/actions?workflow=Test)
See usage examples for `@octokit/auth-app` below the examples for `@octokit/app`.
<!-- toc -->
# app.js
- [Usage](#usage)
- [Examples](#examples)
- [Constructor](#constructor)
- [API](#api)
- [`app.octokit`](#appoctokit)
- [`app.log`](#applog)
- [`app.getInstallationOctokit`](#appgetinstallationoctokit)
- [`app.eachInstallation`](#appeachinstallation)
- [`app.eachRepository`](#appeachrepository)
- [`app.webhooks`](#appwebhooks)
- [`app.oauth`](#appoauth)
- [Middlewares](#middlewares)
- [`getNodeMiddleware(app, options)`](#getnodemiddlewareapp-options)
- [Contributing](#contributing)
- [License](#license)
> GitHub App Authentication client for JavaScript
<!-- tocstop -->
[![@latest](https://img.shields.io/npm/v/@octokit/app.svg)](https://www.npmjs.com/package/@octokit/app)
[![Test](https://github.com/octokit/app.js/workflows/Test/badge.svg)](https://github.com/octokit/app.js/actions?query=workflow%3ATest)
`@octokit/app` has methods to receive tokens for a GitHub app and its installations. The tokens can then be used to interact with GitHub’s [REST API](https://developer.github.com/v3/) or [GraphQL API](https://developer.github.com/v4/). Note that `@octokit/app` does not have methods to send any requests, you will need to use your own request library such as [`@octokit/request`](https://github.com/octokit/request). Alternatively you can use the [`octokit`](https://github.com/octokit/octokit.js) package which comes with everything you need to integrate with any of GitHub’s APIs.
## Usage

@@ -23,22 +33,63 @@

<tr><th>
Browsers
</th><td width=100%>
Load <code>@octokit/app</code> directly from <a href="https://unpkg.com">unpkg.com</a>
```html
<script type="module">
import { App } from "https://unpkg.com/@octokit/app";
</script>
```
`@octokit/app` is not meant for browser usage.
</td></tr>
<tr><th>
Node
</th><td>
Install with <code>npm install @octokit/app</code>
Install with `npm install @octokit/app`
```js
const { App } = require("@octokit/app");
// or: import { App } from "@octokit/app";
const { App, getNodeMiddleware } = require("@octokit/app");
const app = new App({
appId: 123,
privateKey: "-----BEGIN PRIVATE KEY-----\n...",
oauth: {
clientId: "0123",
clientSecret: "0123secret",
},
webhooks: {
secret: "secret",
},
});
const { data } = await app.octokit.request("/app");
console.log("authenticated as %s", response.data.name);
for await (const { octokit, repository } of app.eachRepository.iterator()) {
await octokit.request("POST /repos/{owner}/{repo}/dispatches", {
owner: repository.owner.login,
repo: repository.name,
event_type: "my_event",
});
}
app.webhooks.on("issues.opened", async ({ octokit, payload }) => {
await octokit.request(
"POST /repos/{owner}/{repo}/issues/{issue_number}/comments",
{
owner: payload.repository.owner.login,
repo: payload.repository.name,
issue_number: payload.issue.number,
body: "Hello World!",
}
);
});
app.oauth.on("token", async ({ token, octokit }) => {
const { data } = await octokit.request("GET /user");
console.log(`Token retrieved for ${data.login}`);
});
require("http").createServer(getNodeMiddleware(app)).listen(3000);
// can now receive requests at /api/github/*
```

@@ -50,204 +101,319 @@

## Authenticating as an App
## Examples
In order to authenticate as a GitHub App, you need to generate a Private Key and use it to sign a JSON Web Token (jwt) and encode it. See also the [GitHub Developer Docs](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/).
TBD
Here is how the code looks like with the deprecated `@octokit/app` package.
## Constructor
```js
const { App } = require("@octokit/app");
<table width="100%">
<thead align=left>
<tr>
<th width=150>
name
</th>
<th width=70>
type
</th>
<th>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th>
<code>appId</code>
</th>
<th>
<code>number</code>
</th>
<td>
<strong>Required</strong>. Find the <strong>App ID</strong> on the app’s about page in settings.
</td>
</tr>
<tr>
<th>
<code>privateKey</code>
</th>
<th>
<code>string</code>
</th>
<td>
<strong>Required</strong>. Content of the <code>*.pem</code> file you downloaded from the app’s about page. You can generate a new private key if needed.
</td>
</tr>
<tr id="constructor-option-octokit">
<th>
<code>Octokit</code>
</th>
<th>
<code>Constructor</code>
</th>
<td>
const app = new App({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
});
const jwt = app.getSignedJsonWebToken();
```
You can pass in your own Octokit constructor with custom defaults and plugins. Note that `authStrategy` will be always be set to `createAppAuth` from [`@octokit/auth-app`](https://github.com/octokit/auth-app.js).
To achive the same with [`@octokit/auth-app`](https://github.com/octokit/auth-app.js/#readme), do the following
For usage with enterprise, set `baseUrl` to the hostname + `/api/v3`. Example:
```js
const { createAppAuth } = require("@octokit/auth-app");
const { request } = require("@octokit/request");
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
const { Octokit } = require("@octokit/core");
new App({
appId: 123,
privateKey: "-----BEGIN PRIVATE KEY-----\n...",
oauth: {
clientId: 123,
clientSecret: "secret",
},
webhooks: {
secret: "secret",
},
Octokit: Octokit.defaults({
baseUrl: "https://ghe.my-company.com/api/v3",
}),
});
auth({ type: "app" }).then((authentication) => {
const jwt = authentication.token;
});
```
## Authenticating as an Installation
Defaults to [`@octokit/core`](https://github.com/octokit/core.js).
Once you have authenticated as a GitHub App, you can use that in order to request an installation access token. Calling `requestToken()` automatically performs the app authentication for you. See also the [GitHub Developer Docs](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-an-installation).
</td></tr>
<tr id="constructor-option-log">
<th>
<code>log</code>
</th>
<th>
<code>object</code>
</th>
<td>
Used for internal logging. Defaults to <a href="https://developer.mozilla.org/en-US/docs/Web/API/console"><code>console</code></a>.
</td>
</tr>
<tr>
<th>
<code>webhooks.secret</code>
</th>
<th>
<code>string</code>
</th>
<td>
<strong>Required.</strong> Secret as configured in the GitHub App's settings.
</td>
</tr>
<tr>
<th>
<code>webhooks.transform</code>
</th>
<th>
<code>function</code>
</th>
<td>
Only relevant for `app.webhooks.on`. Transform emitted event before calling handlers. Can be asynchronous.
</td>
</tr>
<tr>
<th>
<code>oauth.clientId</code>
</th>
<th>
<code>number</code>
</th>
<td>
Find the OAuth <strong>Client ID</strong> on the app’s about page in settings.
</td>
</tr>
<tr>
<th>
<code>oauth.clientSecret</code>
</th>
<th>
<code>number</code>
</th>
<td>
Find the OAuth <strong>Client Secret</strong> on the app’s about page in settings.
</td>
</tr>
<tr>
<th>
<code>oauth.allowSignup</code>
</th>
<th>
<code>boolean</code>
</th>
<td>
Sets the default value for <code>app.oauth.getAuthorizationUrl(options)</code>.
</td>
</tr>
<tr>
<th>
<code>oauth.defaultScopes</code>
</th>
<th>
<code>Array of strings</code>
</th>
<td>
Here is how the code looks like with the deprecated `@octokit/app` package.
Sets the default <code>scopes</code> value for <code>app.oauth.getAuthorizationUrl(options)</code>. See [available scopes](https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes)
```js
const { App } = require("@octokit/app");
const { request } = require("@octokit/request");
</td></tr>
</tbody>
</table>
const APP_ID = 1; // replace with your app ID
const PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\n..."; // replace with contents of your private key. Replace line breaks with \n
## API
const app = new App({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY
});
await app.getInstallationAccessToken({
installationId: process.env.INSTALLATION_ID
}).then(installationAccessToken => {
// https://developer.github.com/v3/issues/#create-an-issue
await request("POST /repos/:owner/:repo/issues", {
headers: {
authorization: `token ${installationAccessToken}`,
},
mediaType: {
previews: ["machine-man"]
},
owner: "hiimbex",
repo: "testing-things",
title: "My installation’s first issue"
});
})
```
### `app.octokit`
To achive the same with [`@octokit/auth-app`](https://github.com/octokit/auth-app.js/#readme), do the following
Octokit instance. Uses the [`Octokit` constructor option](#constructor-option-octokit) if passed.
```js
const { createAppAuth } = require("@octokit/auth-app");
const { request } = require("@octokit/request");
### `app.log`
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
installationId: process.env.INSTALLATION_ID
})
See https://github.com/octokit/core.js#logging. Customize using the [`log` constructor option](#constructor-option-log).
auth({ type: "installation" }).then(authentication => {
const installationAccessToken = authentication.token
### `app.getInstallationOctokit`
// https://developer.github.com/v3/issues/#create-an-issue
await request("POST /repos/:owner/:repo/issues", {
headers: {
authorization: `token ${installationAccessToken}`
},
mediaType: {
previews: ["machine-man"]
}
owner: "hiimbex",
repo: "testing-things",
title: "My installation’s first issue"
});
})
```js
const octokit } = await app.getInstallationOctokit(123)
```
Or utilizing the [request hook API](https://github.com/octokit/request.js#authentication)
### `app.eachInstallation`
```js
const { createAppAuth } = require("@octokit/auth-app");
const { request } = require("@octokit/request");
for await (const { octokit, installation } of app.eachInstallation.iterator()) { /* ... */ }
await app.eachInstallation(({ octokit, installation }) => /* ... */)
```
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
installationId: process.env.INSTALLATION_ID,
});
### `app.eachRepository`
const requestWithAuth = request.defaults({
request: {
hook: auth.hook,
},
mediaType: {
previews: ["machine-man"],
},
});
// https://developer.github.com/v3/issues/#create-an-issue
await requestWithAuth("POST /repos/:owner/:repo/issues", {
owner: "hiimbex",
repo: "testing-things",
title: "My installation’s first issue",
});
```js
for await (const { octokit, repository } of app.eachRepository.iterator()) { /* ... */ }
await app.eachRepository(({ octokit, repository }) => /* ... */)
```
## Caching installation tokens
Optionally pass installation ID to iterate through all repositories in one installation
Installation tokens expire after an hour. By default, each `App` instance is caching up to 15000 tokens simultaneously using [`lru-cache`](https://github.com/isaacs/node-lru-cache). You can pass your own cache implementation by passing `options.cache.{get,set}` to the constructor.
```js
for await (const { octokit, repository } of app.eachRepository.iterator({ installationId })) { /* ... */ }
await app.eachRepository({ installationId }, ({ octokit, repository }) => /* ... */)
```
Here is how the code looks like with the deprecated `@octokit/app` package.
### `app.webhooks`
```js
const { App } = require("@octokit/app");
An [`@octokit/webhooks` instance](https://github.com/octokit/webhooks.js/#readme)
const CACHE = {};
### `app.oauth`
const app = new App({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
cache: {
get(key) {
return CACHE[key];
},
set(key, value) {
CACHE[key] = value;
},
},
});
```
An [`@octokit/oauth-app` instance](https://github.com/octokit/oauth-app.js/#readme)
`options.cache` is the same for [`@octokit/auth-app`](https://github.com/octokit/auth-app.js/#readme)'s `createAppAuth(options)`
## Middlewares
```js
const { createAppAuth } = require("@octokit/auth-app");
A middleware is a method or set of methods to handle requests for common environments.
const CACHE = {};
By default, all middlewares expose the following routes
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
cache: {
get(key) {
return CACHE[key];
},
set(key, value) {
CACHE[key] = value;
},
},
});
```
| Route | Route Description |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /api/github/webhooks` | Endpoint to receive GitHub Webhook Event requests |
| `GET /api/github/oauth/login` | Redirects to GitHub's authorization endpoint. Accepts optional `?state` and `?scopes` query parameters. `?scopes` is a comma-separated list of [supported OAuth scope names](https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/#available-scopes) |
| `GET /api/github/oauth/callback` | The client's redirect endpoint. This is where the `token` event gets triggered |
| `POST /api/github/oauth/token` | Exchange an authorization code for an OAuth Access token. If successful, the `token` event gets triggered. |
| `GET /api/github/oauth/token` | Check if token is valid. Must authenticate using token in `Authorization` header. Uses GitHub's [`POST /applications/:client_id/token`](https://developer.github.com/v3/apps/oauth_applications/#check-a-token) endpoint |
| `PATCH /api/github/oauth/token` | Resets a token (invalidates current one, returns new token). Must authenticate using token in `Authorization` header. Uses GitHub's [`PATCH /applications/:client_id/token`](https://developer.github.com/v3/apps/oauth_applications/#reset-a-token) endpoint. |
| `DELETE /api/github/oauth/token` | Invalidates current token, basically the equivalent of a logout. Must authenticate using token in `Authorization` header. |
| `DELETE /api/github/oauth/grant` | Revokes the user's grant, basically the equivalent of an uninstall. must authenticate using token in `Authorization` header. |
## Using with GitHub Enterprise
### `getNodeMiddleware(app, options)`
The `baseUrl` option can be used to override default GitHub's `https://api.github.com`:
Native http server middleware for Node.js
```js
const { App, getNodeMiddleware } = require("@octokit/app");
const app = new App({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
baseUrl: "https://github-enterprise.com/api/v3",
appId: 123,
privateKey: "-----BEGIN PRIVATE KEY-----\n...",
oauth: {
clientId: "0123",
clientSecret: "0123secret",
},
webhooks: {
secret: "secret",
},
});
const middleware = getNodeMiddleware(app);
require("http").createServer(middleware).listen(3000);
// can now receive user authorization callbacks at /api/github/*
```
The same option exist for [`@octokit/auth-app`](https://github.com/octokit/auth-app.js/#readme)'s `createAppAuth(options)`
<table width="100%">
<thead align=left>
<tr>
<th width=150>
name
</th>
<th width=70>
type
</th>
<th>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th>
<code>app</code>
</th>
<th>
<code>App instance</code>
</th>
<td>
<strong>Required</strong>.
</td>
</tr>
<tr>
<th>
<code>options.pathPrefix</code>
</th>
<th>
<code>string</code>
</th>
<td>
All exposed paths will be prefixed with the provided prefix. Defaults to `"/api/github"`
</td>
</tr>
<tr>
<th>
<code>options.onUnhandledRequest</code>
</th>
<th>
<code>function</code>
</th>
<td>
Defaults to
```js
const auth = createAppAuth({
id: process.env.APP_ID,
privateKey: process.env.PRIVATE_KEY,
cache: {
get(key) {
return CACHE[key];
},
set(key, value) {
CACHE[key] = value;
},
},
});
function onUnhandledRequest(request, response) {
response.writeHead(400, {
"content-type": "application/json",
});
response.end(
JSON.stringify({
error: error.message,
})
);
}
```
</td></tr>
</tbody>
</table>
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md)
## License
[MIT](LICENSE)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc