https://github.com/gr2m/universal-github-app-jwt
Calculate GitHub App bearer tokens for Node & modern browsers
https://github.com/gr2m/universal-github-app-jwt
Last synced: over 1 year ago
JSON representation
Calculate GitHub App bearer tokens for Node & modern browsers
- Host: GitHub
- URL: https://github.com/gr2m/universal-github-app-jwt
- Owner: gr2m
- License: mit
- Created: 2019-08-31T18:06:07.000Z (almost 7 years ago)
- Default Branch: main
- Last Pushed: 2025-03-17T22:35:30.000Z (over 1 year ago)
- Last Synced: 2025-03-28T11:45:46.551Z (over 1 year ago)
- Language: JavaScript
- Homepage:
- Size: 919 KB
- Stars: 30
- Watchers: 3
- Forks: 12
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# universal-github-app-jwt
> Calculate GitHub App bearer tokens for Node, Deno, and modern browsers
[](https://www.npmjs.com/universal-github-app-jwt)
[](https://github.com/gr2m/universal-github-app-jwt/actions?query=workflow%3ATest+branch%3Amaster)
## Usage
Browsers
Load universal-github-app-jwt directly from esm.sh
```html
import githubAppJwt from "https://esm.sh/universal-github-app-jwt";
```
Node
Install with npm install universal-github-app-jwt
```js
import githubAppJwt from "universal-github-app-jwt";
```
Deno
Load universal-github-app-jwt directly from esm.sh, including types.
```js
import githubAppJwt from "https://esm.sh/universal-github-app-jwt";
```
```js
const { token, appId, expiration } = await githubAppJwt({
id: APP_ID,
privateKey: PRIVATE_KEY,
});
```
The retrieved `token` can now be used in Authorization request header, e.g. with [`@octokit/request`](https://github.com/octokit/request.js/#readme):
```js
request("GET /app", {
headers: {
authorization: `bearer ${token}`,
},
});
```
For a complete implementation of GitHub App authentication strategies, see [`@octokit/auth-app.js`](https://github.com/octokit/auth-app.js/#readme).
## `githubAppJwt(options)`
name
type
description
options.id
number | string
Required. The GitHub App's ID or Client ID. For github.com and GHES 3.14+, it is recommended to use the Client ID.
options.privateKey
string
Required. Content of the *.pem file you downloaded from the app’s about page. You can generate a new private key if needed. Make sure to preserve the line breaks. If your private key contains escaped newlines (`\\n`), they will be automatically replaced with actual newlines.
options.now
number
An optional override for the current time in seconds since the UNIX epoch. Defaults to Math.floor(Date.now() / 1000)). This value can be overridden to account for a time skew between the local machine and the authentication server.
`githubAppJwt(options)` resolves with an object with the following keys
name
type
description
token
string
The JSON Web Token (JWT) to authenticate as the app.
appId
number
The GitHub App database ID or Client ID passed in options.id.
expiration
number
Timestamp as UNIX epoch, e.g. 1530922170. A Date object can be created using new Date(authentication.expiration).
## About Private Key formats
When downloading a `private-key.pem` file from GitHub, the format is in `PKCS#1` format. Unfortunately, the WebCrypto API only supports `PKCS#8`.
If you use 1Password to store a private key as an SSH key, it will be transformed to the `OpenSSH` format, which is also not supported by WebCrypto.
You can identify the format based on the the first line
| First Line | Format |
| ------------------------------------- | ------- |
| `-----BEGIN RSA PRIVATE KEY-----` | PKCS#1 |
| `-----BEGIN PRIVATE KEY-----` | PKCS#8 |
| `-----BEGIN OPENSSH PRIVATE KEY-----` | OpenSSH |
### Converting `PKCS#1` to `PKCS#8`
- #### Using an Online Private Key Converter
Convert quickly using the Web interface at https://private-key-converter.vercel.app
- #### Using Node.js
If you use Node.js, you can convert the format before passing it to `universal-github-app-jwt`:
```js
import crypto from "node:crypto";
import githubAppJwt from "universal-github-app-jwt";
const privateKeyPkcs8 = crypto
.createPrivateKey(process.env.PRIVATE_KEY)
.export({
type: "pkcs8",
format: "pem",
});
const { token, appId, expiration } = await githubAppJwt({
id: process.env.APP_ID,
privateKey: privateKeyPkcs8,
});
```
- #### Using OpenSSL
Convert the format using `openssl` before passing it to your app.
```
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key
```
### Converting `OpenSSH` to `PKCS#8`
```
cp private-key.pem private-key-pkcs8.key && ssh-keygen -p -m PKCS8 -N "" -f private-key-pkcs8.key
```
This command forces a format change by asking `ssh-keygen` to set no password and then output in a different format.
I'm looking for help to create a minimal `OpenSSH` to `PKCS` convert library that I can recommend people to use before passing the private key to `githubAppJwt`. Please create an issue if you'd like to help.
## License
[MIT](LICENSE)