# 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
```
|
|
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 -m PKCS8 -N "" -f private-key-pkcs8.key
```
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)