Here’s a js version which works fine for me.
Perhaps the issues above were due to mis-matched methods, or maybe not having the scopes that a given resource requires?
package.json
:
{
"name": "js-jwt-test",
"version": "0.0.1",
"main": "index.js",
"license": "MIT",
"dependencies": {
"atlassian-jwt": "^1.0.2",
"axios": "^0.19.0",
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
index.js
const jwt = require('atlassian-jwt');
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const baseUrl = process.argv[2];
const appKey = 'js-jwt-test';
const app = express();
app.use(bodyParser.json());
const clients = {};
app.get('/', (_, res) => {
res.redirect('/descriptor');
});
app.get('/descriptor', (_, res) => {
res.json({
key: appKey,
baseUrl: baseUrl,
authentication: { type: 'jwt' },
scopes: ['READ'],
lifecycle: {
installed: '/register',
enabled: '/ping',
},
});
});
app.post('/register', (req, res) => {
clients[req.body.clientKey] = req.body;
res.sendStatus(204);
});
app.post('/ping', async (req, res) => {
const clientKey = authenticate(req);
const secret = clients[clientKey].sharedSecret;
const clientBaseUrl = clients[clientKey].baseUrl;
const path = '/rest/api/latest/issue/TEST-2';
const response = await axios.get(path, {
baseURL: clientBaseUrl,
headers: {
'Authorization': `JWT ${sign(secret, 'GET', path)}`,
},
});
console.log(response.data);
res.sendStatus(204);
});
function authenticate(req) {
const token = req.headers.authorization.substring('JWT '.length);
const rawPayload = jwt.decode(token, '', true);
const secret = clients[rawPayload.iss].sharedSecret;
const verifiedPayload = jwt.decode(token, secret);
if (verifiedPayload.qsh !== jwt.createQueryStringHash(jwt.fromExpressRequest(req), false, baseUrl)) {
throw new Error('query string hashes did not match');
}
return verifiedPayload.iss;
}
function sign(secret, method, url) {
const nowMs = (new Date()).getTime()
return jwt.encode({
iss: appKey,
aud: appKey,
iat: nowMs - 1000,
exp: nowMs + 10000,
qsh: jwt.createQueryStringHash(jwt.fromMethodAndUrl(method, url)),
}, secret);
}
app.listen(6000);
to run:
node index.js https://base-url-of-your-app