|
1 | 1 | # universal-github-app-jwt |
2 | 2 |
|
3 | | -> Calculate GitHub App bearer tokens for Node & modern browsers |
| 3 | +> Calculate GitHub App bearer tokens for Node, Deno, and modern browsers |
4 | 4 |
|
5 | | -[](https://www.npmjs.com/packageuniversal-github-app-jwt) |
| 5 | +[](https://www.npmjs.com/universal-github-app-jwt) |
6 | 6 | [](https://github.com/gr2m/universal-github-app-jwt/actions?query=workflow%3ATest+branch%3Amaster) |
7 | 7 |
|
8 | | -⚠ The private keys provide by GitHub are in `PKCS#1` format, but the WebCrypto API only supports `PKCS#8`. And neither Node nor the WEbCrypto API supports private keys in the `OpenSSH` format. You can see the difference in the first line, `PKCS#1` format starts with `-----BEGIN RSA PRIVATE KEY-----` while `PKCS#8` starts with `-----BEGIN PRIVATE KEY-----`, and `OpenSSH` starts with `-----BEGIN OPENSSH PRIVATE KEY-----`. |
9 | | - |
10 | | -You can convert `PKCS#1` to `PKCS#8` using `oppenssl`: |
11 | | - |
12 | | -``` |
13 | | -openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key |
14 | | -``` |
15 | | - |
16 | | -You can convert `OpenSSH` to `PKCS#8` using `ssh-keygen`: |
17 | | - |
18 | | -``` |
19 | | -cp private-key.pem private-key-pkcs8.key && ssh-keygen -m PKCS8 -N "" -f private-key-pkcs8.key |
20 | | -``` |
21 | | - |
22 | | -It's also possible to convert the formats with JavaScript, e.g. using [node-rsa](https://github.com/rzcoder/node-rsa), but it turns a 4kb to a 200kb+ built. I'm looking for help to create a minimal `PKCS#1` to `PKCS#8` 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. The same to convert `OpenSSH` to `PKCS#8`. |
23 | | - |
24 | | -You can convert `PKCS#1` to `PKCS#8` in Node.js using the built-in `crypto` module: |
25 | | - |
26 | | -```js |
27 | | -const crypto = require("crypto"); |
28 | | -const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- |
29 | | -... |
30 | | ------END RSA PRIVATE KEY-----`; |
31 | | - |
32 | | -const privateKeyPkcs8 = crypto.createPrivateKey(PRIVATE_KEY).export({ |
33 | | - type: "pkcs8", |
34 | | - format: "pem", |
35 | | -}); |
36 | | -``` |
37 | | - |
38 | | -When using a node, a conversion is not necessary, the implementation is agnostic to either `PKCS` format. |
39 | | - |
40 | | -However, if you got the error `Private Key is in PKCS#1 format, but only PKCS#8 is supported.` inside Node.js, it is possible that your bundler or your app framework incorrectly bundled the web version instead of the node version ([example](https://github.com/backstage/backstage/issues/9959)). |
41 | | - |
42 | 8 | ## Usage |
43 | 9 |
|
44 | 10 | <table> |
@@ -205,6 +171,57 @@ For a complete implementation of GitHub App authentication strategies, see [`@oc |
205 | 171 | </tbody> |
206 | 172 | </table> |
207 | 173 |
|
| 174 | +<!-- do not remove this anchor, it's used in error messages --> |
| 175 | + |
| 176 | +<a name="private-key-formats"></a> |
| 177 | + |
| 178 | +## About Private Key formats |
| 179 | + |
| 180 | +When downloading a `private-key.pem` file from GitHub, the format is in `PKCS#1` format. Unfortunately, the WebCrypto API only supports `PKCS#8`. |
| 181 | + |
| 182 | +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. |
| 183 | + |
| 184 | +You can identify the format based on the the first line |
| 185 | + |
| 186 | +| First Line | Format | |
| 187 | +| ------------------------------------- | ------- | |
| 188 | +| `-----BEGIN RSA PRIVATE KEY-----` | PKCS#1 | |
| 189 | +| `-----BEGIN PRIVATE KEY-----` | PKCS#8 | |
| 190 | +| `-----BEGIN OPENSSH PRIVATE KEY-----` | OpenSSH | |
| 191 | + |
| 192 | +### Converting `PKCS#1` to `PKCS#8` |
| 193 | + |
| 194 | +If you use Node.js, you can convert the format before passing it to `universal-github-app-jwt`: |
| 195 | + |
| 196 | +```js |
| 197 | +import crypto from "node:crypto"; |
| 198 | +import githubAppJwt from "universal-github-app-jwt"; |
| 199 | + |
| 200 | +const privateKeyPkcs8 = crypto.createPrivateKey(process.env.PRIVATE_KEY).export({ |
| 201 | + type: "pkcs8", |
| 202 | + format: "pem", |
| 203 | +} |
| 204 | + |
| 205 | +const { token, appId, expiration } = await githubAppJwt({ |
| 206 | + id: process.env.APP_ID, |
| 207 | + privateKey: privateKeyPkcs8, |
| 208 | +}); |
| 209 | +``` |
| 210 | +
|
| 211 | +But we recommend to convert the format using `openssl` before passing it to your app. |
| 212 | +
|
| 213 | +``` |
| 214 | +openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key |
| 215 | +``` |
| 216 | +
|
| 217 | +### Converting `OpenSSH` to `PKCS#8` |
| 218 | +
|
| 219 | +``` |
| 220 | +cp private-key.pem private-key-pkcs8.key && ssh-keygen -m PKCS8 -N "" -f private-key-pkcs8.key |
| 221 | +``` |
| 222 | +
|
| 223 | +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. |
| 224 | +
|
208 | 225 | ## License |
209 | 226 |
|
210 | 227 | [MIT](LICENSE) |
0 commit comments