Reputation: 511
I'm trying to automate the process outlined on this page using Node.js.
So far I've come up with the following:
const axios = require("axios");
var fs = require('fs');
var NodeRSA = require('node-rsa');
var jwt = require("jsonwebtoken");
exports.openedPOST = function openedPOST(req, res) {
// Private key contents
var private_pem = fs.readFileSync("test-runner.pem");
var key = new NodeRSA({b: 512});
var private_key = key.encrypt(private_pem, 'base64');
// generate jwt
const now = Math.round(Date.now() / 1000);
const payload = {
// issued at time
iat : now,
// expires in 10min
exp : now + (10 * 60),
// Github app id
iss : 7233
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256' })
// auth to github
var instance = axios({
method: "get",
url: "https://api.github.com/app",
headers: {
"Accept" : "application/vnd.github.machine-man-preview+json",
"Authorization" : `Bearer ${token}`
}
})
.then(function(response) {
console.log("Response: ",response.data);
})
.catch(function(error) {
console.warn("Unable to authenticate");
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
if (error.response) {
console.warn(`Status ${error.response.status}`);
console.warn(`${error.response.data.message}`);
}
});
};
exports.openedPOST();
This gives me the following error:
crypto.js:331
var ret = this._handle.sign(toBuf(key), passphrase, rsaPadding,
^
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Sign.sign (crypto.js:331:26)
at Object.sign (/modules/jwa/index.js:55:45)
at Object.jwsSign [as sign] (/modules/jws/lib/sign-stream.js:23:24)
at Object.module.exports [as sign] (/modules/jsonwebtoken/sign.js:186:16)
at Object.openedPOST (GenerateAccessToken.js:29:21)
at Object.<anonymous> (GenerateAccessToken.js:58:9)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
I think the issue has something to do with the private_key
generation as when I manually generate a private_key and hard code it in place of jwt.sign(payload, private_key, { algorithm: 'RS256' })
I get the result I'd expect.
Thoughts around what might be wrong are that new NodeRSA({b: 512});
should be something different. I thought it might be new NodeRSA({b: 256});
but this gives me the following error:
/Users/paulcarron/Desktop/node_modules/jsonwebtoken/sign.js:97
throw err;
^
Error: secretOrPrivateKey must have a value
at Object.module.exports [as sign] (/modules/jsonwebtoken/sign.js:101:20)
at Object.openedPOST (GenerateAccessToken.js:29:21)
at Object.<anonymous> (GenerateAccessToken.js:58:9)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
Another thought was that the contenes of test-runner.pem
was incorrect but it does begin with -----BEGIN RSA PRIVATE KEY-----
and end with -----END RSA PRIVATE KEY-----
. Also, I use the same file when manually generating the token. However, if I write private_pem to console it prints the following:
<Buffer 2d 2d 2d 2d 2d 42 45 47 49 4e 20 52 53 41 20 50 52 49 56 41 54 45 20 4b 45 59 2d 2d 2d 2d 2d 0a 4d 49 49 45 6f 77 49 42 41 41 4b 43 41 51 45 41 31 65 ... >
I;m not sure if that's correct or not.
What am I doing wrong?
Upvotes: 2
Views: 693
Reputation: 511
I got this working.
const axios = require("axios");
var fs = require('fs');
var jwt = require("jsonwebtoken");
var gitInstallationAccessToken = {
genJWTToken: function() {
// Private key contents
var private_key = fs.readFileSync("./path/to/my/pem_file.pem");
// generate jwt
const now = Math.round(Date.now() / 1000);
const payload = {
// issued at time
iat : now,
// expires in 10min
exp : now + (10 * 60),
// Github app id
iss : 1234
};
const token = jwt.sign(payload, private_key, { algorithm: 'RS256' })
return token;
},
genInstallationAccessToken: function(callback) {
var instance = axios({
method: "post",
url: "https://api.github.com/installations/1234/access_tokens",
headers: {
"Accept" : "application/vnd.github.machine-man-preview+json",
"Authorization" : `Bearer ` + gitInstallationAccessToken.genJWTToken()
}
})
.then(function(response) {
callback(response.data.token);
})
.catch(function(error) {
console.warn("Unable to authenticate");
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
if (error.response) {
console.warn(`Status ${error.response.status}`);
console.warn(`${error.response.data.message}`);
}
});
}
}
module.exports = gitInstallationAccessToken;
Upvotes: 3