@seibert/atlassian-connect-tooling
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -96,2 +96,4 @@ /// <reference types="node" /> | ||
* BaseUrl of the requests. Gets passed as baseUrl param to Atlassians jwt library. Can be omitted if pathname is set correctly | ||
* @param additionalClaims | ||
* Additional claims to be appended to JWT payload. Can be used to override aspects of the JWT or to enrich it with additional context information like a userId | ||
* | ||
@@ -142,3 +144,3 @@ * @example | ||
**/ | ||
export declare function createJwtForRequestAuthorization({ tenantData, issuer, expirationInSeconds, request: { method, pathname, body, query }, baseUrl }: CreateJwtForRequestParams): string; | ||
export declare function createJwtForRequestAuthorization({ tenantData, issuer, expirationInSeconds, request: { method, pathname, body, query }, baseUrl, additionalClaims, }: CreateJwtForRequestParams): string; | ||
export interface CreateJwtForRequestParams { | ||
@@ -150,4 +152,5 @@ tenantData: TenantDataWithSharedSecret & TenantDataWithClientKey; | ||
baseUrl?: string; | ||
additionalClaims?: Partial<JwtPayload>; | ||
} | ||
export {}; |
@@ -1,1 +0,1 @@ | ||
var H=Object.create;var y=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var A=e=>y(e,"__esModule",{value:!0});var F=(e,t)=>{A(e);for(var n in t)y(e,n,{get:t[n],enumerable:!0})},$=(e,t,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of D(t))!Q.call(e,r)&&r!=="default"&&y(e,r,{get:()=>t[r],enumerable:!(n=W(t,r))||n.enumerable});return e},m=e=>$(A(y(e!=null?H(K(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);F(exports,{composeAtlassianConnectInstallationMiddleware:()=>E,composeAtlassianRequestAuthenticationMiddleware:()=>P,createJwtForRequestAuthorization:()=>T});var J=m(require("atlassian-jwt")),g=m(require("atlassian-jwt"));var h=m(require("atlassian-jwt"));function x({baseUrl:e,qsh:t,request:n}){let r=(0,h.createQueryStringHash)(n,!1,e);if(t===r)return{successful:!0};let a=(0,h.createQueryStringHash)(n,!0,e);if(t===a)return{successful:!0};let s=(0,h.createCanonicalRequest)(n,!0,e),o=`Auth failure: Query hash mismatch: Received: "${t}" but calculated "${r} ${r!==a&&`and ${a}`}. Requests canonically expression was: "${s}"`;return{successful:!1,error:o}}function b(e,t,{expectedAudience:n,expectedIssuer:r,request:a}){let s=(0,J.decodeAsymmetric)(e,t,g.AsymmetricAlgorithm.RS256,!1),o=u=>u.replace(/\/$/,""),d=o(n);if(!s.aud||!Array.isArray(s.aud))throw new Error(`Jwt token invalid. It is missing a valid aud claim. ${s.aud}`);if(!s.aud.map(o).includes(d))throw new Error(`Jwt token invalid. Expected audience not part of jwt tokens audiences. (${s.aud})`);if(!s.iss)throw new Error("Jwt token invalid. It is missing an iss claim.");if(s.iss!==r)throw new Error("Jwt token invalid. Invalid issuer.");if(!s.qsh)throw new Error("Jwt token invalid. Does not contain qsh claim.");let{successful:c,error:l}=x({baseUrl:n,qsh:s.qsh,request:a});if(!c)throw new Error(`Jwt token invalid. Query hash mismatch. ${l}`);if(!s.exp||typeof s.exp!="number")throw new Error("Jwt token invalid. Does not contain exp claim.");if(Math.floor(new Date().getTime()/1e3)>=s.exp)throw new Error("Jwt token invalid. Expired token.");return s}function j(e){try{return JSON.parse(Buffer.from(e,"base64").toString())}catch(t){return console.error("Could not decode JWT header. Returning null instead.",t),null}}var v=m(require("node-fetch"));async function C({url:e}){let t=await(0,v.default)(e);if(!t.ok)throw new Error(`Could not fetch RSA public key. Host responded with ${t.status}. ${t.statusText}.`);return await t.text()}var S=m(require("atlassian-jwt")),z="https://connect-install-keys.atlassian.com/";function E({baseUrl:e}){return function(n,r,a){var l;let s=n.get("Authorization");if(!s){r.status(401).send("Could not find Authorization header.");return}let o=s.substring(4),[d]=o.split("."),c=j(d);if(!(c==null?void 0:c.kid)){r.status(400).send("Jwt header has an unexpected form.");return}if(!((l=n.body)==null?void 0:l.clientKey)){r.status(401).send("Could not find clientKey on body.");return}C({url:z+c.kid}).then(i=>{try{n.validatedJwtPayload=b(o,i,{expectedAudience:e,expectedIssuer:n.body.clientKey,request:(0,S.fromExpressRequest)(n)}),a()}catch(u){r.status(401).send("Could not decode jwt token."+u)}}).catch(i=>{r.status(401).send("Could not obtain rsaPublicKey"+i)})}}function k(e){var s,o;let t=(s=e.query)==null?void 0:s.jwt,n=(o=e.body)==null?void 0:o.jwt;if(!t&&!e.body)return console.warn("Cannot find JWT token in query parameters. Please include body-parser middleware and parse the urlencoded body (See https://github.com/expressjs/body-parser) if the add-on is rendering in POST mode. Otherwise please ensure the jwt parameter is presented in query."),null;let r=M(e);if(t&&n)return console.warn("JWT token can only appear in either query parameter or request body."),null;let a=t||n||r;return a||(console.warn("JWT token not found in request query, body or authorization header."),null)}function M(e){var n;let t=(n=e.headers)==null?void 0:n.authorization;return t&&t.indexOf("JWT ")===0?t.substring(4):null}var f=m(require("atlassian-jwt"));function P({baseUrl:e,fetchTenantByClientKey:t,requestsForQshValidation:n}){return function(a,s,o){let d=k(a);if(!d){s.status(401).send("Could not find JWT.");return}let c;try{c=(0,f.decodeSymmetric)(d,"",f.SymmetricAlgorithm.HS256,!0)}catch(i){s.status(401).send("Invalid JWT."+i);return}let l=c.iss;if(!l){s.status(401).send("JWT did not contain the issuer (iss) claim");return}t(l).then(i=>{if(!(i==null?void 0:i.sharedSecret)){s.status(401).send("Could not obtain shared secret stored for client");return}let u;try{u=(0,f.decodeSymmetric)(d,i.sharedSecret,f.SymmetricAlgorithm.HS256,!1)}catch(p){s.status(401).send("Unable to decode JWT."+p);return}if(!u.exp||typeof u.exp!="number"||Math.round(new Date().getTime()/1e3)>=u.exp){s.status(401).send("Jwt token invalid. Does not contain an valid exp claim.");return}let R=(n||[(0,f.fromExpressRequest)(a)]).map(p=>x({baseUrl:e,qsh:u.qsh,request:p})).reduce((p,q)=>({successful:q.successful||p.successful,errors:[...p.errors,q.error].filter(I=>I)}),{successful:!1,errors:[]});if(!R.successful){s.status(401).send("Jwt token invalid. Does not contain an valid qsh claim. "+R.errors.join(", "));return}a.atlassianVerified={clientKey:u.iss,userAccountId:u.sub,jwtPayload:u,tenant:i},o()}).catch(i=>{s.status(400).send("Request could not be validated."+i)})}}var w=m(require("atlassian-jwt"));function T({tenantData:e,issuer:t,expirationInSeconds:n=300,request:{method:r="GET",pathname:a="",body:s,query:o},baseUrl:d}){let c=Math.floor(new Date().getTime()/1e3),l={iss:t,iat:c,exp:c+n,aud:[e.clientKey],qsh:(0,w.createQueryStringHash)({method:r,pathname:a,body:s,query:o},!!s,d)};return(0,w.encodeSymmetric)(l,e.sharedSecret,w.SymmetricAlgorithm.HS256)}0&&(module.exports={composeAtlassianConnectInstallationMiddleware,composeAtlassianRequestAuthenticationMiddleware,createJwtForRequestAuthorization}); | ||
var Q=Object.create;var h=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames,J=Object.getOwnPropertySymbols,z=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty,M=Object.prototype.propertyIsEnumerable;var g=(e,t,s)=>t in e?h(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s,b=(e,t)=>{for(var s in t||(t={}))A.call(t,s)&&g(e,s,t[s]);if(J)for(var s of J(t))M.call(t,s)&&g(e,s,t[s]);return e};var j=e=>h(e,"__esModule",{value:!0});var O=(e,t)=>{j(e);for(var s in t)h(e,s,{get:t[s],enumerable:!0})},V=(e,t,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of $(t))!A.call(e,r)&&r!=="default"&&h(e,r,{get:()=>t[r],enumerable:!(s=F(t,r))||s.enumerable});return e},m=e=>V(j(h(e!=null?Q(z(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);O(exports,{composeAtlassianConnectInstallationMiddleware:()=>I,composeAtlassianRequestAuthenticationMiddleware:()=>W,createJwtForRequestAuthorization:()=>D});var v=m(require("atlassian-jwt")),C=m(require("atlassian-jwt"));var y=m(require("atlassian-jwt"));function x({baseUrl:e,qsh:t,request:s}){let r=(0,y.createQueryStringHash)(s,!1,e);if(t===r)return{successful:!0};let a=(0,y.createQueryStringHash)(s,!0,e);if(t===a)return{successful:!0};let n=(0,y.createCanonicalRequest)(s,!0,e),i=`Auth failure: Query hash mismatch: Received: "${t}" but calculated "${r} ${r!==a&&`and ${a}`}. Requests canonically expression was: "${n}"`;return{successful:!1,error:i}}function S(e,t,{expectedAudience:s,expectedIssuer:r,request:a}){let n=(0,v.decodeAsymmetric)(e,t,C.AsymmetricAlgorithm.RS256,!1),i=c=>c.replace(/\/$/,""),l=i(s);if(!n.aud||!Array.isArray(n.aud))throw new Error(`Jwt token invalid. It is missing a valid aud claim. ${n.aud}`);if(!n.aud.map(i).includes(l))throw new Error(`Jwt token invalid. Expected audience not part of jwt tokens audiences. (${n.aud})`);if(!n.iss)throw new Error("Jwt token invalid. It is missing an iss claim.");if(n.iss!==r)throw new Error("Jwt token invalid. Invalid issuer.");if(!n.qsh)throw new Error("Jwt token invalid. Does not contain qsh claim.");let{successful:u,error:d}=x({baseUrl:s,qsh:n.qsh,request:a});if(!u)throw new Error(`Jwt token invalid. Query hash mismatch. ${d}`);if(!n.exp||typeof n.exp!="number")throw new Error("Jwt token invalid. Does not contain exp claim.");if(Math.floor(new Date().getTime()/1e3)>=n.exp)throw new Error("Jwt token invalid. Expired token.");return n}function k(e){try{return JSON.parse(Buffer.from(e,"base64").toString())}catch(t){return console.error("Could not decode JWT header. Returning null instead.",t),null}}var E=m(require("node-fetch"));async function P({url:e}){let t=await(0,E.default)(e);if(!t.ok)throw new Error(`Could not fetch RSA public key. Host responded with ${t.status}. ${t.statusText}.`);return await t.text()}var T=m(require("atlassian-jwt")),N="https://connect-install-keys.atlassian.com/";function I({baseUrl:e}){return function(s,r,a){var d;let n=s.get("Authorization");if(!n){r.status(401).send("Could not find Authorization header.");return}let i=n.substring(4),[l]=i.split("."),u=k(l);if(!(u==null?void 0:u.kid)){r.status(400).send("Jwt header has an unexpected form.");return}if(!((d=s.body)==null?void 0:d.clientKey)){r.status(401).send("Could not find clientKey on body.");return}P({url:N+u.kid}).then(o=>{try{s.validatedJwtPayload=S(i,o,{expectedAudience:e,expectedIssuer:s.body.clientKey,request:(0,T.fromExpressRequest)(s)}),a()}catch(c){r.status(401).send("Could not decode jwt token."+c)}}).catch(o=>{r.status(401).send("Could not obtain rsaPublicKey"+o)})}}function H(e){var n,i;let t=(n=e.query)==null?void 0:n.jwt,s=(i=e.body)==null?void 0:i.jwt;if(!t&&!e.body)return console.warn("Cannot find JWT token in query parameters. Please include body-parser middleware and parse the urlencoded body (See https://github.com/expressjs/body-parser) if the add-on is rendering in POST mode. Otherwise please ensure the jwt parameter is presented in query."),null;let r=B(e);if(t&&s)return console.warn("JWT token can only appear in either query parameter or request body."),null;let a=t||s||r;return a||(console.warn("JWT token not found in request query, body or authorization header."),null)}function B(e){var s;let t=(s=e.headers)==null?void 0:s.authorization;return t&&t.indexOf("JWT ")===0?t.substring(4):null}var f=m(require("atlassian-jwt"));function W({baseUrl:e,fetchTenantByClientKey:t,requestsForQshValidation:s}){return function(a,n,i){let l=H(a);if(!l){n.status(401).send("Could not find JWT.");return}let u;try{u=(0,f.decodeSymmetric)(l,"",f.SymmetricAlgorithm.HS256,!0)}catch(o){n.status(401).send("Invalid JWT."+o);return}let d=u.iss;if(!d){n.status(401).send("JWT did not contain the issuer (iss) claim");return}t(d).then(o=>{if(!(o==null?void 0:o.sharedSecret)){n.status(401).send("Could not obtain shared secret stored for client");return}let c;try{c=(0,f.decodeSymmetric)(l,o.sharedSecret,f.SymmetricAlgorithm.HS256,!1)}catch(p){n.status(401).send("Unable to decode JWT."+p);return}if(!c.exp||typeof c.exp!="number"||Math.round(new Date().getTime()/1e3)>=c.exp){n.status(401).send("Jwt token invalid. Does not contain an valid exp claim.");return}let R=(s||[(0,f.fromExpressRequest)(a)]).map(p=>x({baseUrl:e,qsh:c.qsh,request:p})).reduce((p,q)=>({successful:q.successful||p.successful,errors:[...p.errors,q.error].filter(K=>K)}),{successful:!1,errors:[]});if(!R.successful){n.status(401).send("Jwt token invalid. Does not contain an valid qsh claim. "+R.errors.join(", "));return}a.atlassianVerified={clientKey:c.iss,userAccountId:c.sub,jwtPayload:c,tenant:o},i()}).catch(o=>{n.status(400).send("Request could not be validated."+o)})}}var w=m(require("atlassian-jwt"));function D({tenantData:e,issuer:t,expirationInSeconds:s=300,request:{method:r="GET",pathname:a="",body:n,query:i},baseUrl:l,additionalClaims:u={}}){let d=Math.floor(new Date().getTime()/1e3),o=b({iss:t,iat:d,exp:d+s,aud:[e.clientKey],qsh:(0,w.createQueryStringHash)({method:r,pathname:a,body:n,query:i},!!n,l)},u);return(0,w.encodeSymmetric)(o,e.sharedSecret,w.SymmetricAlgorithm.HS256)}0&&(module.exports={composeAtlassianConnectInstallationMiddleware,composeAtlassianRequestAuthenticationMiddleware,createJwtForRequestAuthorization}); |
{ | ||
"name": "@seibert/atlassian-connect-tooling", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Provides authentication & utility methods for Atlassian Connect apps running on Express.", | ||
@@ -5,0 +5,0 @@ "main": "out/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19390
174