github-app-auth-kit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +193 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +290 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emeka Orji
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# github-app-auth-kit
|
|
2
|
+
|
|
3
|
+
A minimal, dependency-free TypeScript toolkit for GitHub App authentication.
|
|
4
|
+
|
|
5
|
+
Use it to:
|
|
6
|
+
|
|
7
|
+
- mint short-lived GitHub App JWTs
|
|
8
|
+
- resolve installation IDs from `owner/repo`
|
|
9
|
+
- create installation access tokens
|
|
10
|
+
- work in Node, edge runtimes, and GitHub Enterprise
|
|
11
|
+
|
|
12
|
+
## Why this library
|
|
13
|
+
|
|
14
|
+
- Small surface area with strong types
|
|
15
|
+
- Works in three styles: one-shot, client instance, or low-level calls
|
|
16
|
+
- Runtime-agnostic (bring your own `fetch` if needed)
|
|
17
|
+
- Designed for clear errors and predictable behavior
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add github-app-auth-kit
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
29
|
+
|
|
30
|
+
const auth = new GitHubAppAuth({
|
|
31
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
32
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const jwt = auth.createJwt();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Client instance (recommended for multiple calls)
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
44
|
+
|
|
45
|
+
const auth = new GitHubAppAuth({
|
|
46
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
47
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
48
|
+
owner: 'acme',
|
|
49
|
+
repo: 'platform',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const installationId = await auth.resolveInstallationId();
|
|
53
|
+
const token = await auth.createAccessToken();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Resolve installation id for any repo
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
60
|
+
|
|
61
|
+
const auth = new GitHubAppAuth({
|
|
62
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
63
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const installationId = await auth.resolveInstallationId({
|
|
67
|
+
owner: 'acme',
|
|
68
|
+
repo: 'platform',
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Create access token with a known installation id
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
76
|
+
|
|
77
|
+
const auth = new GitHubAppAuth({
|
|
78
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
79
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
80
|
+
installationId: 12345678,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const token = await auth.createAccessToken();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### One-shot access token
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
90
|
+
|
|
91
|
+
const token = await GitHubAppAuth.createAccessToken({
|
|
92
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
93
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
94
|
+
installationId: 12345678,
|
|
95
|
+
permissions: {
|
|
96
|
+
contents: 'read',
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### GitHub Enterprise
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
105
|
+
|
|
106
|
+
const auth = new GitHubAppAuth({
|
|
107
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
108
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
109
|
+
apiBaseUrl: 'https://github.example.com/api/v3',
|
|
110
|
+
installationId: 12345678,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const token = await auth.createAccessToken();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Custom fetch (edge runtimes or Node <18)
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { GitHubAppAuth } from 'github-app-auth-kit';
|
|
120
|
+
import { fetch as undiciFetch } from 'undici';
|
|
121
|
+
|
|
122
|
+
const auth = new GitHubAppAuth({
|
|
123
|
+
appId: process.env.GITHUB_APP_ID!,
|
|
124
|
+
privateKey: process.env.GITHUB_PRIVATE_KEY!,
|
|
125
|
+
installationId: 12345678,
|
|
126
|
+
fetch: undiciFetch,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const token = await auth.createAccessToken();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## API
|
|
133
|
+
|
|
134
|
+
### `new GitHubAppAuth(options)`
|
|
135
|
+
|
|
136
|
+
| Option | Type | Required | Description |
|
|
137
|
+
| ---------------- | ------------------ | -------- | ------------------------------------------------- |
|
|
138
|
+
| `appId` | `number \| string` | Yes | GitHub App id. |
|
|
139
|
+
| `privateKey` | `string` | Yes | PEM private key (supports `\n` escaped newlines). |
|
|
140
|
+
| `owner` | `string` | No | Default repository owner. |
|
|
141
|
+
| `repo` | `string` | No | Default repository name. |
|
|
142
|
+
| `installationId` | `number \| string` | No | Default installation id for tokens. |
|
|
143
|
+
| `apiBaseUrl` | `string` | No | Override REST API base URL (GitHub Enterprise). |
|
|
144
|
+
| `fetch` | `typeof fetch` | No | Provide `fetch` for non-standard runtimes. |
|
|
145
|
+
|
|
146
|
+
### `auth.createJwt()`
|
|
147
|
+
|
|
148
|
+
Returns a short-lived GitHub App JWT. JWTs are valid for 10 minutes maximum; this library issues 9-minute tokens with a 60-second clock skew.
|
|
149
|
+
|
|
150
|
+
### `auth.resolveInstallationId({ owner, repo })`
|
|
151
|
+
|
|
152
|
+
Resolves the installation id for the given repository. Uses the default `owner`/`repo` if set on the constructor.
|
|
153
|
+
|
|
154
|
+
### `auth.createAccessToken(options)`
|
|
155
|
+
|
|
156
|
+
Creates an installation access token. You can provide:
|
|
157
|
+
|
|
158
|
+
- `installationId` to skip repository lookup
|
|
159
|
+
- `owner` and `repo` to look up installation id on demand
|
|
160
|
+
- optional `permissions`, `repositories`, and `repositoryIds` for fine-grained tokens
|
|
161
|
+
|
|
162
|
+
### `GitHubAppAuth.createAccessToken(options)`
|
|
163
|
+
|
|
164
|
+
Convenience one-call helper that creates a client and returns an access token.
|
|
165
|
+
|
|
166
|
+
## Error handling
|
|
167
|
+
|
|
168
|
+
All network errors and non-2xx GitHub API responses throw descriptive errors that include the HTTP status and response body.
|
|
169
|
+
|
|
170
|
+
## Security notes
|
|
171
|
+
|
|
172
|
+
- Treat `privateKey`, JWTs, and access tokens as secrets.
|
|
173
|
+
- Do not log tokens or private keys.
|
|
174
|
+
- Issue JWTs only when needed; they expire quickly.
|
|
175
|
+
|
|
176
|
+
## Runtime support
|
|
177
|
+
|
|
178
|
+
- Node.js 18+ (native `fetch`)
|
|
179
|
+
- Other runtimes: pass a `fetch` implementation in the constructor
|
|
180
|
+
|
|
181
|
+
## Troubleshooting
|
|
182
|
+
|
|
183
|
+
- If you see "`fetch` is not available in this runtime", pass a `fetch` implementation.
|
|
184
|
+
- If you see "Missing repository target", provide both `owner` and `repo`, or use `installationId`.
|
|
185
|
+
|
|
186
|
+
## Related links
|
|
187
|
+
|
|
188
|
+
- [GitHub Apps documentation](https://docs.github.com/en/apps/creating-github-apps)
|
|
189
|
+
- [GitHub REST API](https://docs.github.com/en/rest)
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
type FetchLike = typeof fetch;
|
|
2
|
+
type PermissionLevel = 'read' | 'write';
|
|
3
|
+
type InstallationTokenPermissions = Record<string, PermissionLevel>;
|
|
4
|
+
type GitHubRepoRef = {
|
|
5
|
+
owner: string;
|
|
6
|
+
repo: string;
|
|
7
|
+
};
|
|
8
|
+
type ResolveInstallationIdOptions = Partial<GitHubRepoRef>;
|
|
9
|
+
type CreateAccessTokenOptions = ResolveInstallationIdOptions & {
|
|
10
|
+
installationId?: number | undefined;
|
|
11
|
+
permissions?: InstallationTokenPermissions | undefined;
|
|
12
|
+
repositories?: string[] | undefined;
|
|
13
|
+
repositoryIds?: number[] | undefined;
|
|
14
|
+
};
|
|
15
|
+
type GitHubAppAuthOptions = {
|
|
16
|
+
appId: number | string;
|
|
17
|
+
privateKey?: string | undefined;
|
|
18
|
+
privateKeyRaw?: string | undefined;
|
|
19
|
+
owner?: string | undefined;
|
|
20
|
+
repo?: string | undefined;
|
|
21
|
+
installationId?: number | undefined;
|
|
22
|
+
apiBaseUrl?: string | undefined;
|
|
23
|
+
fetch?: FetchLike | undefined;
|
|
24
|
+
};
|
|
25
|
+
declare function generateGitHubAppJwt(appId: number | string, privateKeyRaw: string): string;
|
|
26
|
+
declare class GitHubAppAuth {
|
|
27
|
+
private readonly appId;
|
|
28
|
+
private readonly privateKey;
|
|
29
|
+
private readonly owner;
|
|
30
|
+
private readonly repo;
|
|
31
|
+
private readonly installationId;
|
|
32
|
+
private readonly apiBaseUrl;
|
|
33
|
+
private readonly fetchImpl;
|
|
34
|
+
constructor({ appId, privateKey, privateKeyRaw, owner, repo, installationId, apiBaseUrl, fetch, }: GitHubAppAuthOptions);
|
|
35
|
+
createJwt(): string;
|
|
36
|
+
resolveInstallationId(options?: ResolveInstallationIdOptions): Promise<number>;
|
|
37
|
+
createAccessToken(options?: CreateAccessTokenOptions): Promise<string>;
|
|
38
|
+
withContext(context: Partial<Pick<GitHubAppAuthOptions, 'owner' | 'repo' | 'installationId'>>): GitHubAppAuth;
|
|
39
|
+
static createAccessToken(options: GitHubAppAuthOptions & CreateAccessTokenOptions): Promise<string>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type CreateAccessTokenOptions, GitHubAppAuth, type GitHubAppAuthOptions, type GitHubRepoRef, type InstallationTokenPermissions, type ResolveInstallationIdOptions, generateGitHubAppJwt };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,MAAM,CAyBR;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
function toBase64UrlJson(value) {
|
|
6
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
var DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
|
|
11
|
+
function normalizePrivateKey(privateKeyRaw) {
|
|
12
|
+
return privateKeyRaw.replace(/\\n/g, "\n");
|
|
13
|
+
}
|
|
14
|
+
function requireNonEmptyString(value, fieldName) {
|
|
15
|
+
const trimmed = value.trim();
|
|
16
|
+
if (!trimmed) {
|
|
17
|
+
throw new Error(`\`${fieldName}\` must be a non-empty string.`);
|
|
18
|
+
}
|
|
19
|
+
return trimmed;
|
|
20
|
+
}
|
|
21
|
+
function normalizeOptionalNonEmptyString(value, fieldName) {
|
|
22
|
+
if (value === void 0) {
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
return requireNonEmptyString(value, fieldName);
|
|
26
|
+
}
|
|
27
|
+
function resolvePrivateKey({
|
|
28
|
+
privateKey,
|
|
29
|
+
privateKeyRaw
|
|
30
|
+
}) {
|
|
31
|
+
const key = privateKey ?? privateKeyRaw;
|
|
32
|
+
if (key === void 0) {
|
|
33
|
+
throw new Error("Either `privateKey` or `privateKeyRaw` is required.");
|
|
34
|
+
}
|
|
35
|
+
return requireNonEmptyString(key, "privateKey");
|
|
36
|
+
}
|
|
37
|
+
function resolveFetch(fetchOverride) {
|
|
38
|
+
const fetchImpl = fetchOverride ?? globalThis.fetch;
|
|
39
|
+
if (typeof fetchImpl !== "function") {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"A fetch implementation is required. Pass `fetch` in options when global fetch is unavailable."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return fetchImpl;
|
|
45
|
+
}
|
|
46
|
+
function resolveApiBaseUrl(apiBaseUrl) {
|
|
47
|
+
return apiBaseUrl ? requireNonEmptyString(apiBaseUrl, "apiBaseUrl") : DEFAULT_GITHUB_API_BASE_URL;
|
|
48
|
+
}
|
|
49
|
+
function parsePositiveInteger(value, fieldName) {
|
|
50
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
51
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
52
|
+
throw new Error(`\`${fieldName}\` must be a positive integer.`);
|
|
53
|
+
}
|
|
54
|
+
return parsed;
|
|
55
|
+
}
|
|
56
|
+
function parseOptionalInstallationId(value) {
|
|
57
|
+
if (value === void 0) {
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
return parsePositiveInteger(value, "installationId");
|
|
61
|
+
}
|
|
62
|
+
function resolveRepoRef({
|
|
63
|
+
defaultOwner,
|
|
64
|
+
defaultRepo,
|
|
65
|
+
owner,
|
|
66
|
+
repo
|
|
67
|
+
}) {
|
|
68
|
+
const resolvedOwner = owner ?? defaultOwner;
|
|
69
|
+
const resolvedRepo = repo ?? defaultRepo;
|
|
70
|
+
if (!resolvedOwner || !resolvedRepo) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
"Missing repository target. Provide both `owner` and `repo` in the constructor or method call."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
owner: resolvedOwner,
|
|
77
|
+
repo: resolvedRepo
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function buildAccessTokenRequestBody({
|
|
81
|
+
permissions,
|
|
82
|
+
repositories,
|
|
83
|
+
repositoryIds
|
|
84
|
+
}) {
|
|
85
|
+
const body = {};
|
|
86
|
+
if (permissions) {
|
|
87
|
+
body.permissions = permissions;
|
|
88
|
+
}
|
|
89
|
+
if (repositories?.length) {
|
|
90
|
+
body.repositories = repositories;
|
|
91
|
+
}
|
|
92
|
+
if (repositoryIds?.length) {
|
|
93
|
+
body.repository_ids = repositoryIds;
|
|
94
|
+
}
|
|
95
|
+
if (Object.keys(body).length === 0) {
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
return JSON.stringify(body);
|
|
99
|
+
}
|
|
100
|
+
async function throwGitHubApiError(response, context) {
|
|
101
|
+
const responseBodyRaw = await response.text();
|
|
102
|
+
const responseBody = responseBodyRaw.trim().length > 0 ? responseBodyRaw : "(empty response body)";
|
|
103
|
+
throw new Error(
|
|
104
|
+
`${context} (${response.status} ${response.statusText}): ${responseBody}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
async function requestInstallationId({
|
|
108
|
+
owner,
|
|
109
|
+
repo,
|
|
110
|
+
appJwt,
|
|
111
|
+
apiBaseUrl,
|
|
112
|
+
fetchImpl
|
|
113
|
+
}) {
|
|
114
|
+
const encodedOwner = encodeURIComponent(owner);
|
|
115
|
+
const encodedRepo = encodeURIComponent(repo);
|
|
116
|
+
const response = await fetchImpl(
|
|
117
|
+
`${apiBaseUrl}/repos/${encodedOwner}/${encodedRepo}/installation`,
|
|
118
|
+
{
|
|
119
|
+
headers: {
|
|
120
|
+
Accept: "application/vnd.github+json",
|
|
121
|
+
Authorization: `Bearer ${appJwt}`
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
return throwGitHubApiError(
|
|
127
|
+
response,
|
|
128
|
+
`Failed to read installation for ${owner}/${repo}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const payload = await response.json();
|
|
132
|
+
if (!payload.id) {
|
|
133
|
+
throw new Error("GitHub response did not include an installation id.");
|
|
134
|
+
}
|
|
135
|
+
return payload.id;
|
|
136
|
+
}
|
|
137
|
+
async function requestAccessToken({
|
|
138
|
+
installationId,
|
|
139
|
+
appJwt,
|
|
140
|
+
apiBaseUrl,
|
|
141
|
+
fetchImpl,
|
|
142
|
+
tokenOptions
|
|
143
|
+
}) {
|
|
144
|
+
const body = buildAccessTokenRequestBody(tokenOptions);
|
|
145
|
+
const headers = {
|
|
146
|
+
Accept: "application/vnd.github+json",
|
|
147
|
+
Authorization: `Bearer ${appJwt}`
|
|
148
|
+
};
|
|
149
|
+
if (body) {
|
|
150
|
+
headers["Content-Type"] = "application/json";
|
|
151
|
+
}
|
|
152
|
+
const response = await fetchImpl(
|
|
153
|
+
`${apiBaseUrl}/app/installations/${installationId}/access_tokens`,
|
|
154
|
+
body ? {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers,
|
|
157
|
+
body
|
|
158
|
+
} : {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
return throwGitHubApiError(
|
|
165
|
+
response,
|
|
166
|
+
`Failed to create installation access token for installation ${installationId}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const payload = await response.json();
|
|
170
|
+
if (!payload.token) {
|
|
171
|
+
throw new Error("GitHub response did not include an installation token.");
|
|
172
|
+
}
|
|
173
|
+
return payload.token;
|
|
174
|
+
}
|
|
175
|
+
function generateGitHubAppJwt(appId, privateKeyRaw) {
|
|
176
|
+
const normalizedAppId = parsePositiveInteger(appId, "appId");
|
|
177
|
+
const privateKey = normalizePrivateKey(privateKeyRaw);
|
|
178
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
179
|
+
const payload = {
|
|
180
|
+
iat: now - 60,
|
|
181
|
+
exp: now + 9 * 60,
|
|
182
|
+
iss: normalizedAppId
|
|
183
|
+
};
|
|
184
|
+
const header = {
|
|
185
|
+
alg: "RS256",
|
|
186
|
+
typ: "JWT"
|
|
187
|
+
};
|
|
188
|
+
const encodedHeader = toBase64UrlJson(header);
|
|
189
|
+
const encodedPayload = toBase64UrlJson(payload);
|
|
190
|
+
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
191
|
+
const signer = crypto.createSign("RSA-SHA256");
|
|
192
|
+
signer.update(signingInput);
|
|
193
|
+
signer.end();
|
|
194
|
+
const signature = signer.sign(privateKey, "base64url");
|
|
195
|
+
return `${signingInput}.${signature}`;
|
|
196
|
+
}
|
|
197
|
+
var GitHubAppAuth = class _GitHubAppAuth {
|
|
198
|
+
appId;
|
|
199
|
+
privateKey;
|
|
200
|
+
owner;
|
|
201
|
+
repo;
|
|
202
|
+
installationId;
|
|
203
|
+
apiBaseUrl;
|
|
204
|
+
fetchImpl;
|
|
205
|
+
constructor({
|
|
206
|
+
appId,
|
|
207
|
+
privateKey,
|
|
208
|
+
privateKeyRaw,
|
|
209
|
+
owner,
|
|
210
|
+
repo,
|
|
211
|
+
installationId,
|
|
212
|
+
apiBaseUrl,
|
|
213
|
+
fetch
|
|
214
|
+
}) {
|
|
215
|
+
this.appId = parsePositiveInteger(appId, "appId");
|
|
216
|
+
this.privateKey = normalizePrivateKey(
|
|
217
|
+
resolvePrivateKey({
|
|
218
|
+
privateKey,
|
|
219
|
+
privateKeyRaw
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
this.owner = normalizeOptionalNonEmptyString(owner, "owner");
|
|
223
|
+
this.repo = normalizeOptionalNonEmptyString(repo, "repo");
|
|
224
|
+
this.installationId = parseOptionalInstallationId(installationId);
|
|
225
|
+
this.apiBaseUrl = resolveApiBaseUrl(apiBaseUrl);
|
|
226
|
+
this.fetchImpl = resolveFetch(fetch);
|
|
227
|
+
if (this.owner && !this.repo || !this.owner && this.repo) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
"Both `owner` and `repo` must be provided together when setting a default repository target."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
createJwt() {
|
|
234
|
+
return generateGitHubAppJwt(this.appId, this.privateKey);
|
|
235
|
+
}
|
|
236
|
+
async resolveInstallationId(options = {}) {
|
|
237
|
+
const repoRef = resolveRepoRef({
|
|
238
|
+
defaultOwner: this.owner,
|
|
239
|
+
defaultRepo: this.repo,
|
|
240
|
+
owner: normalizeOptionalNonEmptyString(options.owner, "owner"),
|
|
241
|
+
repo: normalizeOptionalNonEmptyString(options.repo, "repo")
|
|
242
|
+
});
|
|
243
|
+
return requestInstallationId({
|
|
244
|
+
...repoRef,
|
|
245
|
+
appJwt: this.createJwt(),
|
|
246
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
247
|
+
fetchImpl: this.fetchImpl
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
async createAccessToken(options = {}) {
|
|
251
|
+
const installationId = parseOptionalInstallationId(
|
|
252
|
+
options.installationId ?? this.installationId
|
|
253
|
+
);
|
|
254
|
+
const resolveOptions = {};
|
|
255
|
+
if (options.owner !== void 0) {
|
|
256
|
+
resolveOptions.owner = options.owner;
|
|
257
|
+
}
|
|
258
|
+
if (options.repo !== void 0) {
|
|
259
|
+
resolveOptions.repo = options.repo;
|
|
260
|
+
}
|
|
261
|
+
const resolvedInstallationId = installationId ?? await this.resolveInstallationId(resolveOptions);
|
|
262
|
+
return requestAccessToken({
|
|
263
|
+
installationId: resolvedInstallationId,
|
|
264
|
+
appJwt: this.createJwt(),
|
|
265
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
266
|
+
fetchImpl: this.fetchImpl,
|
|
267
|
+
tokenOptions: options
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
withContext(context) {
|
|
271
|
+
return new _GitHubAppAuth({
|
|
272
|
+
appId: this.appId,
|
|
273
|
+
privateKey: this.privateKey,
|
|
274
|
+
owner: context.owner ?? this.owner,
|
|
275
|
+
repo: context.repo ?? this.repo,
|
|
276
|
+
installationId: context.installationId ?? this.installationId,
|
|
277
|
+
apiBaseUrl: this.apiBaseUrl,
|
|
278
|
+
fetch: this.fetchImpl
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
static async createAccessToken(options) {
|
|
282
|
+
const auth = new _GitHubAppAuth(options);
|
|
283
|
+
return auth.createAccessToken(options);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
export {
|
|
287
|
+
GitHubAppAuth,
|
|
288
|
+
generateGitHubAppJwt
|
|
289
|
+
};
|
|
290
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils.ts"],"sourcesContent":["import crypto from 'node:crypto';\n\nimport { toBase64UrlJson } from './utils';\n\nconst DEFAULT_GITHUB_API_BASE_URL = 'https://api.github.com';\n\ntype FetchLike = typeof fetch;\n\ntype PermissionLevel = 'read' | 'write';\n\nexport type InstallationTokenPermissions = Record<string, PermissionLevel>;\n\nexport type GitHubRepoRef = {\n owner: string;\n repo: string;\n};\n\nexport type ResolveInstallationIdOptions = Partial<GitHubRepoRef>;\n\nexport type CreateAccessTokenOptions = ResolveInstallationIdOptions & {\n installationId?: number | undefined;\n permissions?: InstallationTokenPermissions | undefined;\n repositories?: string[] | undefined;\n repositoryIds?: number[] | undefined;\n};\n\nexport type GitHubAppAuthOptions = {\n appId: number | string;\n privateKey?: string | undefined;\n privateKeyRaw?: string | undefined;\n owner?: string | undefined;\n repo?: string | undefined;\n installationId?: number | undefined;\n apiBaseUrl?: string | undefined;\n fetch?: FetchLike | undefined;\n};\n\ntype InstallationLookupResponse = {\n id?: number;\n};\n\ntype AccessTokenResponse = {\n token?: string;\n};\n\ntype AccessTokenRequestBody = {\n permissions?: InstallationTokenPermissions;\n repositories?: string[];\n repository_ids?: number[];\n};\n\nfunction normalizePrivateKey(privateKeyRaw: string): string {\n return privateKeyRaw.replace(/\\\\n/g, '\\n');\n}\n\nfunction requireNonEmptyString(value: string, fieldName: string): string {\n const trimmed = value.trim();\n if (!trimmed) {\n throw new Error(`\\`${fieldName}\\` must be a non-empty string.`);\n }\n\n return trimmed;\n}\n\nfunction normalizeOptionalNonEmptyString(\n value: string | undefined,\n fieldName: string\n): string | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return requireNonEmptyString(value, fieldName);\n}\n\nfunction resolvePrivateKey({\n privateKey,\n privateKeyRaw,\n}: {\n privateKey?: string | undefined;\n privateKeyRaw?: string | undefined;\n}): string {\n const key = privateKey ?? privateKeyRaw;\n if (key === undefined) {\n throw new Error('Either `privateKey` or `privateKeyRaw` is required.');\n }\n\n return requireNonEmptyString(key, 'privateKey');\n}\n\nfunction resolveFetch(fetchOverride?: FetchLike): FetchLike {\n const fetchImpl = fetchOverride ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new Error(\n 'A fetch implementation is required. Pass `fetch` in options when global fetch is unavailable.'\n );\n }\n\n return fetchImpl;\n}\n\nfunction resolveApiBaseUrl(apiBaseUrl?: string): string {\n return apiBaseUrl\n ? requireNonEmptyString(apiBaseUrl, 'apiBaseUrl')\n : DEFAULT_GITHUB_API_BASE_URL;\n}\n\nfunction parsePositiveInteger(\n value: number | string,\n fieldName: string\n): number {\n const parsed = typeof value === 'number' ? value : Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new Error(`\\`${fieldName}\\` must be a positive integer.`);\n }\n\n return parsed;\n}\n\nfunction parseOptionalInstallationId(\n value: number | undefined\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return parsePositiveInteger(value, 'installationId');\n}\n\nfunction resolveRepoRef({\n defaultOwner,\n defaultRepo,\n owner,\n repo,\n}: {\n defaultOwner: string | undefined;\n defaultRepo: string | undefined;\n owner: string | undefined;\n repo: string | undefined;\n}): GitHubRepoRef {\n const resolvedOwner = owner ?? defaultOwner;\n const resolvedRepo = repo ?? defaultRepo;\n\n if (!resolvedOwner || !resolvedRepo) {\n throw new Error(\n 'Missing repository target. Provide both `owner` and `repo` in the constructor or method call.'\n );\n }\n\n return {\n owner: resolvedOwner,\n repo: resolvedRepo,\n };\n}\n\nfunction buildAccessTokenRequestBody({\n permissions,\n repositories,\n repositoryIds,\n}: CreateAccessTokenOptions): string | undefined {\n const body: AccessTokenRequestBody = {};\n\n if (permissions) {\n body.permissions = permissions;\n }\n\n if (repositories?.length) {\n body.repositories = repositories;\n }\n\n if (repositoryIds?.length) {\n body.repository_ids = repositoryIds;\n }\n\n if (Object.keys(body).length === 0) {\n return undefined;\n }\n\n return JSON.stringify(body);\n}\n\nasync function throwGitHubApiError(\n response: Response,\n context: string\n): Promise<never> {\n const responseBodyRaw = await response.text();\n const responseBody =\n responseBodyRaw.trim().length > 0 ? responseBodyRaw : '(empty response body)';\n\n throw new Error(\n `${context} (${response.status} ${response.statusText}): ${responseBody}`\n );\n}\n\nasync function requestInstallationId({\n owner,\n repo,\n appJwt,\n apiBaseUrl,\n fetchImpl,\n}: {\n owner: string;\n repo: string;\n appJwt: string;\n apiBaseUrl: string;\n fetchImpl: FetchLike;\n}): Promise<number> {\n const encodedOwner = encodeURIComponent(owner);\n const encodedRepo = encodeURIComponent(repo);\n const response = await fetchImpl(\n `${apiBaseUrl}/repos/${encodedOwner}/${encodedRepo}/installation`,\n {\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${appJwt}`,\n },\n }\n );\n\n if (!response.ok) {\n return throwGitHubApiError(\n response,\n `Failed to read installation for ${owner}/${repo}`\n );\n }\n\n const payload = (await response.json()) as InstallationLookupResponse;\n if (!payload.id) {\n throw new Error('GitHub response did not include an installation id.');\n }\n\n return payload.id;\n}\n\nasync function requestAccessToken({\n installationId,\n appJwt,\n apiBaseUrl,\n fetchImpl,\n tokenOptions,\n}: {\n installationId: number;\n appJwt: string;\n apiBaseUrl: string;\n fetchImpl: FetchLike;\n tokenOptions: CreateAccessTokenOptions;\n}): Promise<string> {\n const body = buildAccessTokenRequestBody(tokenOptions);\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${appJwt}`,\n };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n\n const response = await fetchImpl(\n `${apiBaseUrl}/app/installations/${installationId}/access_tokens`,\n body\n ? {\n method: 'POST',\n headers,\n body,\n }\n : {\n method: 'POST',\n headers,\n }\n );\n\n if (!response.ok) {\n return throwGitHubApiError(\n response,\n `Failed to create installation access token for installation ${installationId}`\n );\n }\n\n const payload = (await response.json()) as AccessTokenResponse;\n if (!payload.token) {\n throw new Error('GitHub response did not include an installation token.');\n }\n\n return payload.token;\n}\n\nexport function generateGitHubAppJwt(\n appId: number | string,\n privateKeyRaw: string\n): string {\n const normalizedAppId = parsePositiveInteger(appId, 'appId');\n const privateKey = normalizePrivateKey(privateKeyRaw);\n\n const now = Math.floor(Date.now() / 1000);\n const payload = {\n iat: now - 60,\n exp: now + 9 * 60,\n iss: normalizedAppId,\n };\n\n const header = {\n alg: 'RS256',\n typ: 'JWT',\n };\n\n const encodedHeader = toBase64UrlJson(header);\n const encodedPayload = toBase64UrlJson(payload);\n const signingInput = `${encodedHeader}.${encodedPayload}`;\n\n const signer = crypto.createSign('RSA-SHA256');\n signer.update(signingInput);\n signer.end();\n\n const signature = signer.sign(privateKey, 'base64url');\n return `${signingInput}.${signature}`;\n}\n\nexport class GitHubAppAuth {\n private readonly appId: number;\n private readonly privateKey: string;\n private readonly owner: string | undefined;\n private readonly repo: string | undefined;\n private readonly installationId: number | undefined;\n private readonly apiBaseUrl: string;\n private readonly fetchImpl: FetchLike;\n\n constructor({\n appId,\n privateKey,\n privateKeyRaw,\n owner,\n repo,\n installationId,\n apiBaseUrl,\n fetch,\n }: GitHubAppAuthOptions) {\n this.appId = parsePositiveInteger(appId, 'appId');\n this.privateKey = normalizePrivateKey(\n resolvePrivateKey({\n privateKey,\n privateKeyRaw,\n })\n );\n this.owner = normalizeOptionalNonEmptyString(owner, 'owner');\n this.repo = normalizeOptionalNonEmptyString(repo, 'repo');\n this.installationId = parseOptionalInstallationId(installationId);\n this.apiBaseUrl = resolveApiBaseUrl(apiBaseUrl);\n this.fetchImpl = resolveFetch(fetch);\n\n if ((this.owner && !this.repo) || (!this.owner && this.repo)) {\n throw new Error(\n 'Both `owner` and `repo` must be provided together when setting a default repository target.'\n );\n }\n }\n\n createJwt(): string {\n return generateGitHubAppJwt(this.appId, this.privateKey);\n }\n\n async resolveInstallationId(\n options: ResolveInstallationIdOptions = {}\n ): Promise<number> {\n const repoRef = resolveRepoRef({\n defaultOwner: this.owner,\n defaultRepo: this.repo,\n owner: normalizeOptionalNonEmptyString(options.owner, 'owner'),\n repo: normalizeOptionalNonEmptyString(options.repo, 'repo'),\n });\n\n return requestInstallationId({\n ...repoRef,\n appJwt: this.createJwt(),\n apiBaseUrl: this.apiBaseUrl,\n fetchImpl: this.fetchImpl,\n });\n }\n\n async createAccessToken(options: CreateAccessTokenOptions = {}): Promise<string> {\n const installationId = parseOptionalInstallationId(\n options.installationId ?? this.installationId\n );\n\n const resolveOptions: ResolveInstallationIdOptions = {};\n if (options.owner !== undefined) {\n resolveOptions.owner = options.owner;\n }\n\n if (options.repo !== undefined) {\n resolveOptions.repo = options.repo;\n }\n\n const resolvedInstallationId =\n installationId ?? (await this.resolveInstallationId(resolveOptions));\n\n return requestAccessToken({\n installationId: resolvedInstallationId,\n appJwt: this.createJwt(),\n apiBaseUrl: this.apiBaseUrl,\n fetchImpl: this.fetchImpl,\n tokenOptions: options,\n });\n }\n\n withContext(\n context: Partial<Pick<GitHubAppAuthOptions, 'owner' | 'repo' | 'installationId'>>\n ): GitHubAppAuth {\n return new GitHubAppAuth({\n appId: this.appId,\n privateKey: this.privateKey,\n owner: context.owner ?? this.owner,\n repo: context.repo ?? this.repo,\n installationId: context.installationId ?? this.installationId,\n apiBaseUrl: this.apiBaseUrl,\n fetch: this.fetchImpl,\n });\n }\n\n static async createAccessToken(\n options: GitHubAppAuthOptions & CreateAccessTokenOptions\n ): Promise<string> {\n const auth = new GitHubAppAuth(options);\n return auth.createAccessToken(options);\n }\n}\n","export function toBase64UrlJson(value: Record<string, unknown>): string {\n return Buffer.from(JSON.stringify(value)).toString('base64url');\n}\n"],"mappings":"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","names":[]}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEtE"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAAA,0CAEC;AAFD,SAAgB,eAAe,CAAC,KAA8B;IAC5D,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "github-app-auth-kit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "TypeScript helpers for GitHub App JWTs and installation access tokens.",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"github-app",
|
|
19
|
+
"installation-token",
|
|
20
|
+
"jwt",
|
|
21
|
+
"typescript"
|
|
22
|
+
],
|
|
23
|
+
"author": "Emeka Orji",
|
|
24
|
+
"license": "ISC",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^22.13.10",
|
|
27
|
+
"tsup": "^8.5.1",
|
|
28
|
+
"typescript": "^5.8.2",
|
|
29
|
+
"vitest": "^2.1.9"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
}
|
|
36
|
+
}
|