universal-github-app-jwt
Advanced tools
Comparing version 2.0.1 to 2.0.2
@@ -10,2 +10,8 @@ // @ts-check | ||
export async function getToken({ privateKey, payload }) { | ||
if (privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----")) { | ||
throw new Error( | ||
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS is supported. See https://github.com/gr2m/universal-github-app-jwt#readme" | ||
); | ||
} | ||
return jsonwebtoken.sign(payload, privateKey, { | ||
@@ -12,0 +18,0 @@ algorithm: "RS256", |
@@ -16,8 +16,15 @@ // we don't @ts-check here because it chokes crypto which is a global API in modern JS runtime environments | ||
// WebCrypto only supports PKCS#8, unfortunately | ||
if (/BEGIN RSA PRIVATE KEY/.test(privateKey)) { | ||
if (privateKey.includes("-----BEGIN RSA PRIVATE KEY-----")) { | ||
throw new Error( | ||
"[universal-github-app-jwt] Private Key is in PKCS#1 format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#readme" | ||
"[universal-github-app-jwt] Private Key is in PKCS#1 format, but only PKCS#8 is supported by WebCrypto. See https://github.com/gr2m/universal-github-app-jwt#readme" | ||
); | ||
} | ||
// WebCrypto does not support OpenSSH, unfortunately | ||
if (privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----")) { | ||
throw new Error( | ||
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS#8 is supported by WebCrypto. See https://github.com/gr2m/universal-github-app-jwt#readme" | ||
); | ||
} | ||
const algorithm = { | ||
@@ -24,0 +31,0 @@ name: "RSASSA-PKCS1-v1_5", |
{ | ||
"name": "universal-github-app-jwt", | ||
"type": "module", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"exports": "./index.js", | ||
@@ -6,0 +6,0 @@ "imports": { |
@@ -8,4 +8,6 @@ # universal-github-app-jwt | ||
⚠ The private keys provide by GitHub are in `PKCS#1` format, but the WebCrypto API only supports `PKCS#8`. 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-----`. You can convert one format to the other using `oppenssl`: | ||
⚠ 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-----`. | ||
You can convert `PKCS#1` to `PKCS#8` using `oppenssl`: | ||
``` | ||
@@ -15,7 +17,14 @@ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key | ||
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. | ||
You can convert `OpenSSH` to `PKCS#8` using `ssh-keygen`: | ||
The way it works with `node-rsa` is this | ||
``` | ||
cp private-key.pem private-key-pkcs8.key && ssh-keygen -m PKCS8 -N "" -f private-key-pkcs8.key | ||
``` | ||
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`. | ||
You can convert `PKCS#1` to `PKCS#8` in Node.js using the built-in `crypto` module: | ||
```js | ||
const crypto = require("crypto"); | ||
const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- | ||
@@ -25,13 +34,12 @@ ... | ||
const key = new NodeRSA(PRIVATE_KEY); | ||
const privateKeyPkcs8 = key.exportKey("pkcs8-private-pem"); | ||
// privateKeyPkcs8 is now | ||
// -----BEGIN PRIVATE KEY----- | ||
// ... | ||
// -----END PRIVATE KEY----- | ||
const privateKeyPkcs8 = crypto.createPrivateKey(PRIVATE_KEY).export({ | ||
type: "pkcs8", | ||
format: "pem", | ||
}); | ||
``` | ||
When using a node, a conversion is not necessary, the implementation is agnostic to either format. | ||
When using a node, a conversion is not necessary, the implementation is agnostic to either `PKCS` format. | ||
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)). | ||
## Usage | ||
@@ -38,0 +46,0 @@ |
@@ -65,2 +65,33 @@ import test from "ava"; | ||
-----END PRIVATE KEY-----`; | ||
// openssh version of the key above | ||
// see https://github.com/gr2m/universal-github-app-jwt/issues/72 | ||
const PRIVATEY_KEY_OPENSSH = `-----BEGIN OPENSSH PRIVATE KEY----- | ||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn | ||
NhAAAAAwEAAQAAAQEA1c7+9z5Pad7OejecsQ0bu3aozN3tihPmljnnudb9G3HECdnHlWu2 | ||
/a1gB9JW5TBQ+AVpum9Okx7KfqkfBKL9mcHgSL0yWMdjMfNOqNtrQqKlN4kEp6RD++7sGb | ||
zbfZ9arwrlD/HSDAWGdGGJTSOBM6pHehyLmSC3DJoR/CTu0vTGTWXQrO64Z8tyXQPtVPb/ | ||
YXrcUhbBp8i72b9Xky0fD6PkEebOy0Ip58XVAn2UPNlNOSPSye+Qjtius0Md4Nie4+X8kw | ||
VI2Qjk3dSm0sw/720KJkdVDmrayeljtKBx6AtNQsSXgzQbeMmiqFFkwrG1+zx6E7H7jqIQ | ||
9B6bvWKXGwAAA7hJqTyJSak8iQAAAAdzc2gtcnNhAAABAQDVzv73Pk9p3s56N5yxDRu7dq | ||
jM3e2KE+aWOee51v0bccQJ2ceVa7b9rWAH0lblMFD4BWm6b06THsp+qR8Eov2ZweBIvTJY | ||
x2Mx806o22tCoqU3iQSnpEP77uwZvNt9n1qvCuUP8dIMBYZ0YYlNI4Ezqkd6HIuZILcMmh | ||
H8JO7S9MZNZdCs7rhny3JdA+1U9v9hetxSFsGnyLvZv1eTLR8Po+QR5s7LQinnxdUCfZQ8 | ||
2U05I9LJ75CO2K6zQx3g2J7j5fyTBUjZCOTd1KbSzD/vbQomR1UOatrJ6WO0oHHoC01CxJ | ||
eDNBt4yaKoUWTCsbX7PHoTsfuOohD0Hpu9YpcbAAAAAwEAAQAAAQA/JAQTy+jz4QKlASta | ||
9f4MnHw5FAkET+A22R7fuOfCZRR5vEC+lbLSs5K6fJmA0YX32NFiZ2CS/fLa+OLaIbA26h | ||
RsJsNpiGh45duC7ll8sj+MaQBg6ZfSHLrI1wcS0C6dpuACl21qc29Di1Ja33NWaKD3JNrs | ||
+8ZTCGTrS5Tj4y89g7no1XtuCXMMB860FijnwNdUf/XudA1bHoZ0h/8OOkO+t8uCNBNwSK | ||
FDLKJRCs4dsnQAMs5IGmxkAVLmpmaLTX7yaA13gotSw/MjQlsk5WKSWSQw16KAVORALAr4 | ||
TdbEkaGl1q5TEgwe6/xPmkMirmuCjjar5qCbgttb0inhAAAAgQDOYPZ2JGmhibqKjjLFm0 | ||
qzpcQ6RPvPK1/7g0NInmjPMebP0K6eSPx09/49J6WTD++EajN7FhktUSYxukdWaCocAQJT | ||
DNYP0K88G4rtC2IYy5JFn9SWz5ohx//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapR | ||
aKt6OvSBwy8wAAAIEA7yW6wBkVoNhgXnk8XSZv3W+Q0xtdVpidJeNGBWnczlZrummt4xw3 | ||
xs6zV+rGUDy59yDkKwBKjMMa42Mni7T9Fx8+EKUuhVK3PVQyajoyQqFwT1GORJNzc/eYQ6 | ||
VYOCSC8OyZmsBM2p+0D4FF2/abwSPMmy0NgyFLCUFVc3OECpkAAACBAOTgJiN8LebPnJYN | ||
fKkuwSkdg7jhVq8zVXB2F4Y8fLzklldN9zst8r3VAQIbvQNS1KqcMjGvrpyIMZr5lDEBHc | ||
h0DHIAbFbNdHUf4NsRozC3MI+pJ/sa9yVSGZ20U+dGLj4X/p7NUnHYT+rqaPSNP7EbCLjf | ||
ehm+uSScfeIEOJPTAAAAAAEC | ||
-----END OPENSSH PRIVATE KEY-----`; | ||
// see https://runkit.com/gr2m/reproducable-jwt | ||
@@ -100,2 +131,19 @@ const BEARER = | ||
test("Throw error if key is OpenSSH", async (t) => { | ||
MockDate.set(0); | ||
try { | ||
await githubAppJwt({ | ||
id: APP_ID, | ||
privateKey: PRIVATEY_KEY_OPENSSH, | ||
}); | ||
t.fail("should throw"); | ||
} catch (error) { | ||
t.is( | ||
error.message, | ||
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS is supported. See https://github.com/gr2m/universal-github-app-jwt#readme" | ||
); | ||
} | ||
}); | ||
test("Include the time difference in the expiration and issued_at field", async (t) => { | ||
@@ -102,0 +150,0 @@ MockDate.set(0); |
28917
392
211