atlassian-connect-auth
Version:
Helper for handling webhooks from Atlassian products
124 lines (123 loc) • 4.77 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyAsymmetricConnectJwt = exports.verifyConnectJwt = exports.decodeUnverifiedConnectJwt = exports.isAsymmetricAlgorithm = void 0;
const atlassianJwt = __importStar(require("atlassian-jwt"));
const AuthError_1 = require("./AuthError");
/**
* Checks whether the algorithm is asymmetric. Currently, only RS256 is supported.
*/
function isAsymmetricAlgorithm(alg) {
return alg === atlassianJwt.AsymmetricAlgorithm.RS256;
}
exports.isAsymmetricAlgorithm = isAsymmetricAlgorithm;
/**
* Decodes a Connect JWT without verifying its authenticity.
*/
function decodeUnverifiedConnectJwt(rawConnectJwt) {
try {
const alg = atlassianJwt.getAlgorithm(rawConnectJwt);
if (isAsymmetricAlgorithm(alg)) {
const kid = atlassianJwt.getKeyId(rawConnectJwt);
return {
...(kid ? { kid } : undefined),
alg,
...atlassianJwt.decodeAsymmetric(rawConnectJwt, '', atlassianJwt.AsymmetricAlgorithm.RS256, true),
};
}
return {
alg,
...atlassianJwt.decodeSymmetric(rawConnectJwt, '', atlassianJwt.SymmetricAlgorithm.HS256, true),
};
}
catch (error) {
throw new AuthError_1.AuthError('Failed to decode token', {
code: AuthError_1.AuthErrorCode.FAILED_TO_DECODE,
originError: error,
});
}
}
exports.decodeUnverifiedConnectJwt = decodeUnverifiedConnectJwt;
/**
* Decodes a Connect JWT verifying it against the Shared Secret (provided during installation) and checks expiration.
*/
function verifyConnectJwt({ rawConnectJwt, sharedSecret, unverifiedConnectJwt, }) {
let connectJwt;
try {
const alg = atlassianJwt.getAlgorithm(rawConnectJwt);
connectJwt = {
alg,
...atlassianJwt.decodeSymmetric(rawConnectJwt, sharedSecret, atlassianJwt.SymmetricAlgorithm.HS256),
};
}
catch (error) {
throw new AuthError_1.AuthError('Invalid signature', {
code: AuthError_1.AuthErrorCode.INVALID_SIGNATURE,
originError: error,
unverifiedConnectJwt,
});
}
const now = Math.floor(Date.now() / 1000);
if (connectJwt.exp && now > connectJwt.exp) {
throw new AuthError_1.AuthError('Token expired', {
code: AuthError_1.AuthErrorCode.TOKEN_EXPIRED,
unverifiedConnectJwt: connectJwt,
});
}
return connectJwt;
}
exports.verifyConnectJwt = verifyConnectJwt;
/**
* Decodes an asymmetric Connect JWT verifying it against the public secret (obtained from the CDN by the kid) and
* checks expiration.
*/
function verifyAsymmetricConnectJwt({ rawConnectJwt, publicKey, unverifiedConnectJwt, }) {
let connectJwt;
try {
const alg = atlassianJwt.getAlgorithm(rawConnectJwt);
const kid = atlassianJwt.getKeyId(rawConnectJwt);
connectJwt = {
kid,
alg,
...atlassianJwt.decodeAsymmetric(rawConnectJwt, publicKey, atlassianJwt.AsymmetricAlgorithm.RS256),
};
}
catch (error) {
throw new AuthError_1.AuthError('Invalid signature', {
code: AuthError_1.AuthErrorCode.INVALID_SIGNATURE,
originError: error,
unverifiedConnectJwt,
});
}
const now = Math.floor(Date.now() / 1000);
if (connectJwt.exp && now > connectJwt.exp) {
throw new AuthError_1.AuthError('Token expired', {
code: AuthError_1.AuthErrorCode.TOKEN_EXPIRED,
unverifiedConnectJwt: connectJwt,
});
}
return connectJwt;
}
exports.verifyAsymmetricConnectJwt = verifyAsymmetricConnectJwt;