// we don't @ts-check here because it chokes crypto which is a global API in modern JS runtime environments import { isPkcs1, isOpenSsh, getEncodedMessage, getDERfromPEM, string2ArrayBuffer, base64encode, } from "./utils.js"; import { subtle, convertPrivateKey } from "#crypto"; /** * @param {import('../internals').GetTokenOptions} options * @returns {Promise} */ export async function getToken({ privateKey, payload }) { const convertedPrivateKey = convertPrivateKey(privateKey); // WebCrypto only supports PKCS#8, unfortunately /* 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. See https://github.com/gr2m/universal-github-app-jwt#private-key-formats" ); } /* c8 ignore stop */ // WebCrypto does not support OpenSSH, unfortunately if (isOpenSsh(convertedPrivateKey)) { throw new Error( "[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#private-key-formats" ); } const algorithm = { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" }, }; /** @type {import('../internals').Header} */ const header = { alg: "RS256", typ: "JWT" }; const privateKeyDER = getDERfromPEM(convertedPrivateKey); const importedKey = await subtle.importKey( "pkcs8", privateKeyDER, algorithm, false, ["sign"] ); const encodedMessage = getEncodedMessage(header, payload); const encodedMessageArrBuf = string2ArrayBuffer(encodedMessage); const signatureArrBuf = await subtle.sign( algorithm.name, importedKey, encodedMessageArrBuf ); const encodedSignature = base64encode(signatureArrBuf); return `${encodedMessage}.${encodedSignature}`; }