Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

universal-github-app-jwt

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

universal-github-app-jwt - npm Package Compare versions

Comparing version 2.0.2 to 2.0.3

lib/crypto-native.js

2

index.js
// @ts-check
// @ts-ignore - #get-token is defined in "imports" in package.json
import { getToken } from "#get-token";
import { getToken } from "./lib/get-token.js";

@@ -6,0 +6,0 @@ /**

// we don't @ts-check here because it chokes crypto which is a global API in modern JS runtime environments
import {
isPkcs1,
isOpenSsh,
getEncodedMessage,

@@ -10,2 +12,4 @@ getDERfromPEM,

import { subtle, convertPrivateKey } from "#crypto";
/**

@@ -16,13 +20,17 @@ * @param {import('../internals').GetTokenOptions} options

export async function getToken({ privateKey, payload }) {
const convertedPrivateKey = convertPrivateKey(privateKey);
// WebCrypto only supports PKCS#8, unfortunately
if (privateKey.includes("-----BEGIN RSA PRIVATE KEY-----")) {
/* c8 ignore start */
if (isPkcs1(convertedPrivateKey)) {
throw new Error(
"[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"
"[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"
);
}
/* c8 ignore stop */
// WebCrypto does not support OpenSSH, unfortunately
if (privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----")) {
if (isOpenSsh(convertedPrivateKey)) {
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"
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#readme"
);

@@ -39,4 +47,4 @@ }

const privateKeyDER = getDERfromPEM(privateKey);
const importedKey = await crypto.subtle.importKey(
const privateKeyDER = getDERfromPEM(convertedPrivateKey);
const importedKey = await subtle.importKey(
"pkcs8",

@@ -52,3 +60,3 @@ privateKeyDER,

const signatureArrBuf = await crypto.subtle.sign(
const signatureArrBuf = await subtle.sign(
algorithm.name,

@@ -55,0 +63,0 @@ importedKey,

// we don't @ts-check here because it chokes on atob and btoa which are available in all modern JS runtime environments
/**
* @param {string} privateKey
* @returns {boolean}
*/
export function isPkcs1(privateKey) {
return privateKey.includes("-----BEGIN RSA PRIVATE KEY-----");
}
/**
* @param {string} privateKey
* @returns {boolean}
*/
export function isOpenSsh(privateKey) {
return privateKey.includes("-----BEGIN OPENSSH PRIVATE KEY-----");
}
/**
* @param {string} str

@@ -32,3 +48,2 @@ * @returns {ArrayBuffer}

/**
*
* @param {import('../internals').Header} header

@@ -66,3 +81,2 @@ * @param {import('../internals').Payload} payload

/**
*
* @param {Record<string,unknown>} obj

@@ -69,0 +83,0 @@ * @returns {string}

{
"name": "universal-github-app-jwt",
"type": "module",
"version": "2.0.2",
"version": "2.0.3",
"exports": "./index.js",
"imports": {
"#get-token": {
"node": "./lib/get-token-node.js",
"default": "./lib/get-token.js"
"#crypto": {
"node": "./lib/crypto-node.js",
"default": "./lib/crypto-native.js"
}

@@ -37,8 +37,5 @@ },

"license": "MIT",
"dependencies": {
"jsonwebtoken": "^9.0.0"
},
"devDependencies": {
"ava": "^5.1.0",
"c8": "^7.12.0",
"c8": "^8.0.0",
"esbuild": "^0.16.10",

@@ -50,3 +47,14 @@ "mockdate": "^3.0.5",

"typescript": "^4.9.4"
},
"release": {
"branches": [
"+([0-9]).x",
"main",
"next",
{
"name": "beta",
"prerelease": true
}
]
}
}
# universal-github-app-jwt
> Calculate GitHub App bearer tokens for Node & modern browsers
> Calculate GitHub App bearer tokens for Node, Deno, and modern browsers
[![@latest](https://img.shields.io/npm/vuniversal-github-app-jwt.svg)](https://www.npmjs.com/packageuniversal-github-app-jwt)
[![@latest](https://img.shields.io/npm/universal-github-app-jwt.svg)](https://www.npmjs.com/universal-github-app-jwt)
[![Build Status](https://github.com/gr2m/universal-github-app-jwt/workflows/Test/badge.svg)](https://github.com/gr2m/universal-github-app-jwt/actions?query=workflow%3ATest+branch%3Amaster)
⚠ 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`:
```
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private-key-pkcs8.key
```
You can convert `OpenSSH` to `PKCS#8` using `ssh-keygen`:
```
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-----
...
-----END RSA 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 `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

@@ -208,4 +174,55 @@

<!-- do not remove this anchor, it's used in error messages -->
<a name="private-key-formats"></a>
## 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`
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,
});
```
But we recommend to 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)
import test from "ava";
import MockDate from "mockdate";
import crypto from "node:crypto";
import githubAppJwt from "../index.js";
const APP_ID = 1;
const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY-----
// private key in pkcs1 format, as it's provided by GitHub
const PRIVATE_KEY_PKCS1 = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1c7+9z5Pad7OejecsQ0bu3aozN3tihPmljnnudb9G3HECdnH

@@ -100,3 +104,3 @@ lWu2/a1gB9JW5TBQ+AVpum9Okx7KfqkfBKL9mcHgSL0yWMdjMfNOqNtrQqKlN4kE

test("README example for app auth", async (t) => {
test("README example for app auth with private key in PKCS#8 format", async (t) => {
MockDate.set(0);

@@ -106,3 +110,3 @@

id: APP_ID,
privateKey: PRIVATE_KEY,
privateKey: PRIVATE_KEY_PKCS8,
});

@@ -117,3 +121,3 @@

test("README example for app auth with private key in PKCS#8 format", async (t) => {
test("README example for app auth with private key in PKCS#1 format", async (t) => {
MockDate.set(0);

@@ -123,3 +127,3 @@

id: APP_ID,
privateKey: PRIVATE_KEY_PKCS8,
privateKey: PRIVATE_KEY_PKCS1,
});

@@ -134,3 +138,3 @@

test("Throw error if key is OpenSSH", async (t) => {
test("Throws error if key is OpenSSH", async (t) => {
MockDate.set(0);

@@ -147,3 +151,3 @@

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"
"[universal-github-app-jwt] Private Key is in OpenSSH format, but only PKCS#8 is supported. See https://github.com/gr2m/universal-github-app-jwt#readme"
);

@@ -150,0 +154,0 @@ }

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc