{"_id":"@goodrequest/passport-jwt-wrapper","_rev":"31-d4840fc89bbcc6fe547121dcc4f61782","name":"@goodrequest/passport-jwt-wrapper","dist-tags":{"next":"1.5.1-2","latest":"1.7.1"},"versions":{"1.1.0-beta":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.1.0-beta","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.1.0-beta","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"f669e01edb1973cc0c9c36bd066600671b49e29a","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.1.0-beta.tgz","fileCount":197,"integrity":"sha512-o5RQ6hlrLVwUBvz6CCZO+j1Ee/5qItfukTTKqLK4zmhSvIGhaXpeLosyshTVJCq6Fxuuu9QYlB3jRokBmafEmA==","signatures":[{"sig":"MEQCIHcaxSWn2aNoX41m3lDnSCMtULByeRTkdeLt1vXer/IHAiAc5n7sMeQjo3Q7u5f9SJywiT6xYtlD9KsExme5Fl9pqQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":311732,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjwTxSACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmpowg//YIJDI48xWnxEY3kNfkg3RVFF5wai1mufT/pW0YDC/m7mtxAS\r\n5lwpbPCTVoLUXXQMHc65kcKquLuvTjeXlcQOwPQSeNMrIw0+AZWX1ylIXO9b\r\nzMMoTapZwf5WP2YgMIWTSNyM0rAf8aibra3PTRKOaGtWJC3bRYJm46UpuLQZ\r\nPIIrHmv6ZNN25BSh6o5Q7FeS2v2aS2ub6RaYkXnh8vKDRdo84XR+9xFO4kdu\r\nxXripeCC9b+KRU7kGWsaVTQknga+tsoLbrnnP37hvDyprD1FpX1buABFk5g/\r\nzNCBw6hKb7ow9neG6/Y7AJ7J0632TXz5oVwsHNaAAOPmpvZHCgi7PD0d7qJ9\r\n+g7hQaTWa3kr0Lmvcy1DIEAkkjf12aMuSoFSjNcsJ2LdI2e8mPgQ4zC6ZKBP\r\nqVOIl/002eN6wYHuSi6tm04P+PLtdtl76utVxP2rKrZbzDFh3V2aUSC2EeyH\r\nJNwFTnMj5nahmxDh9XI3lyuH+ZgzuA1BSXxMwNccAcvXBUSuIZcAjw7MLtb7\r\nfb2dLrXRCDezHlwVBT8kaNHn6wMx3oJJ7v3kDmac+bzsDUahFMFeuWHYETrh\r\nQPGxgIJ5juliV0Yr9uv5y+yezZDSSRFFeARyeAMm9XrX4IyjdalVQ98uiOPE\r\n3UqrZP00cKot0RT+hYIkLbdD+dnwwkx5f5Q=\r\n=roYj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"683191a1cbcd0a955bc63b473b16aa467eb0bf49","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{"test":"tests"},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.6","jsonwebtoken":"^8.5.1","passport-jwt":"^4.0.0","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.30.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.1","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.17","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.0","@types/jsonwebtoken":"^8.5.9","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.26.0","@types/passport-local":"^1.0.34","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.1","@typescript-eslint/eslint-plugin":"^5.46.1","@goodrequest/eslint-config-typescript":"^1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.1.0-beta_1673608273875_0.6817218648609753","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.1.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.1.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"7f35957d9af19bb689b98109efa3f7552137f62d","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.1.0.tgz","fileCount":197,"integrity":"sha512-ja/HKwCBAO3EKxDdp1dunOkwlHgTy9H2d8zv2KuIStrg3Q8hlA1s/iZYv7K+ky18PwvrTYJoDxCCtmp4XBMHhw==","signatures":[{"sig":"MEYCIQCNNsBRO8S93U6J5ak/0mIFNIhuzpPJ1NJ8TFQO1tLYVwIhAMm38Ks/vfXf2xujppymleZo+azQ/SwVt98nP8orm2uB","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":310839,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjwVgCACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpGyQ/9EKL/zSflGrXv62Gh/Gv49d4JCDhH7JGpTsZ4UHdrz8gN9Abq\r\nWeJKVUvWM9TCG077n0Le7IB6vD+ZIrP1hx1HULyKQf+K3X3c+Eeyg3g6Egl7\r\nTaOlx88QiGk4UD6E6FBjIYZRKXPEaPGDg2A84jBt+QJzPW9DlbmK2SoACfL9\r\newx+vQ7vH5pM4AS2+4/9O8pxm/LaGdAvOy3OBoE/+GWMBI3cA20pBsYlHlyz\r\ndwfi368KMMOSZ+c1LJGoOgZkQAm1SpkAlDPlrkRUQD9/vOlPmV4hkGzvEjVp\r\nx5nNPTUjylzyyaqKMXwiUB+YPShdwlka6Uev355+X0vFKaQsY+UIYMXXDJLE\r\n2IqOEXW/9uCg2GYsH4Xopk016tj1TtsMat88rf7jjni256Fd0/kb70LVdbS7\r\naO52s9i8t8su/wZ+xdDZtNhUGqyiPSRkY1Z6McakRdzxNvRLO67rNJOhSxKa\r\nt++nJB2l8URdLDuSmnD9i1Zi1zLv5CCnQfnpRF/r2HtbvvjzgTMcNMh8kIH6\r\nwGHnNyIeFaOMuNBQcsd5zoPGqfdrzIqeRsS6NZKQIYvmRKuxtMUQNfhoDfro\r\nleF4Y6FhnB+yInSa32KHeTlSFAX5uPw6tK2xFXPHUiUSguU2pNFSl3ZIVI4u\r\n/kAVXRS0D16dDPZpZjAji4H3O/Jhvc+LOQ0=\r\n=iHuU\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"b82a07d33778d5d71b32648df86e30cddb6406ae","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.6","jsonwebtoken":"^8.5.1","passport-jwt":"^4.0.0","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.30.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.1","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.17","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.0","@types/jsonwebtoken":"^8.5.9","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.26.0","@types/passport-local":"^1.0.34","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.1","@typescript-eslint/eslint-plugin":"^5.46.1","@goodrequest/eslint-config-typescript":"^1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.1.0_1673615361865_0.7018072667056954","host":"s3://npm-registry-packages"}},"1.1.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.1.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.1.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"2efc0f9a6e6e38e0c1ace827153cadc22c84688b","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.1.1.tgz","fileCount":198,"integrity":"sha512-eTd3R7azo0T9FG/xwsDiTrIVeWZnPRotiuQRnVizYCqQJUB6hA9iIhOE0ORHIyPLAXZkGE1onX0SLgcYPL0ScQ==","signatures":[{"sig":"MEYCIQD4/caj5u+RRfO5NhuxLSUz1mUrdINVFhaxcd9ff6MwxAIhAIEu7NwEQV2UaRt1Auo0Q4PFBMclXajYUMHCKtx7UdTs","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":310935,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjxoG8ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrRrBAAggy5odU3OUllza81jlpPPMrX44+2+iHetrt+wHYUEO8dJizA\r\neNKoHtJBwbzSSHiUcGyx/rLe22Q+xsAyk8CwdxEQ4KtiP1kzhA5FD7j0IOm4\r\nRyXNLCQKjX5F9qdMPDm31F4eidoaqIpnPiQkcs/01A5F0N4qIkXOiH5RvE19\r\nl51fb1bgQnoTJo5q4JaKskkX88kUobbDtePbFqwpymhgNzAHMwFhKu6N5c8L\r\nCJrs5NbzbrIEynPnNs92Lp4FfDdGj7JwhX8sS1FzLg1CvdGQBTIQnygz32Xp\r\nAybB6A0mp4IPx6fBs8IumHsZ9Mky2z8WaVTw6R5A4FsSlJJMqElbKeJFDIOW\r\n/yF+0pvqupzivk5q9QWJdkaD+ME1qgN7VJoUaPbg85SdFeDbv9iPV2AVrKXY\r\nVBuJVu4XBWbjGqRshcJkhf8jpYQ2zBv3/Z/Qn+jOpj8mU0az+lBQ/nDtZdsM\r\nM2t57o5LozpDdCCAcYKHMEPPWl/fpos7PJca/Gqoxkplb0/z7S5wwTe7M4mo\r\nAN89oHV0nZ7iYkAf9/FfBW20IT0nGbl6FW4hQrWScfyM+p039Xua7C3d5REc\r\nLF39qr5ctzrfIdR6Z8KWb9SKd1mUxLAljkT4CSZIQhbBYIa6ZpHtTWrCC5Tz\r\nA+nAL/0MvCquFv7uqpI6ffv583KQMJhpVzU=\r\n=4C2w\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"53de5bd01d57c4f9a0b32eea4a834ae4038f739f","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.32.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.1.1_1673953724475_0.7244843837262533","host":"s3://npm-registry-packages"}},"1.2.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.2.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.2.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"a061895d1920d6e9f4138d66712582889a5d5feb","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.2.0.tgz","fileCount":201,"integrity":"sha512-llHVvtDDSn6XU0mg2Kp/R09KCoWi0sCGbFNpuAFIe2pevJZ+tqa6CSilFwNS1hWurugBD7S+Ql7jmSQEgDx7DQ==","signatures":[{"sig":"MEUCIF1kfzQ16IiMQFV1pIZKk7xzeg7ImMBU9e7Swfj06Tl1AiEAw4y3Q3JaON9mwYmODpbsnD/t6J5Yjd/eS7P7oWiuspU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":319121,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjySnZACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp6lhAAmyfn0Dt2+isBuQeNEerDTCPBdsmxxIRrqpLbU2rIUXBzQX4p\r\nik5yuXpprLPTNKltZR4mpIa8Jh4BBn7xcqp4+gu25UtxVgS0oj9LBGfVUrU9\r\n/kc2JO9cjBmpVLdAz9io+Af8C0+15aR9GxokGNLTskbxBqhtbKhoCbr1UPy5\r\nqKSIneQoYkGksvL5XLdF3AKOYDJsb4lkUEqveJFNaE1AB/dFXG6pPGw8XkXw\r\nvHu+AlQMBAffL2/p2RsCYM2gbCOv13uRJaoJIdlSrtVtRcKd+udpGkyVXzOh\r\nZ7xfz01JTOGyIT1cV+u427e2IcFYIqfLXykmwv1kDLlp1BiUvy1gKCx3iuRf\r\n/OCfnP2POtmy3xkgqrxttsyjqSV9bpdjxjmGMzXW4b3goAekuA84/pa1DV+6\r\n2joj7+fpR/ZFjIWbEdASbBZRAeTFlDZZqX6J5hYIAVUcW+1/GrUWCwf9Dweu\r\nYx3w40Kzli+LHgRB6zGdXE6/hBWDe0l4CVM8cc4rxjRQKQcutNthSsKDUwts\r\no5SW/mnp+7TacHMA0a65QPkfgW2Xn2FEAezKOGxZ8dEPKWPWZUYf/krKG+5j\r\nuO6bam4MLa87jNztKC4gfTTdaHApNlF1H3YxQeGkbCU+uapzn0A+fEJBmBhq\r\nTZ9GAUbzJhTbhr/Ve04E8LS4V8sslhwdeLI=\r\n=qR77\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"3cfe14152dbc2dd69ab237a9efacc437f98e87e4","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.32.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.2.0_1674127833564_0.4668255834115831","host":"s3://npm-registry-packages"}},"1.2.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.2.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.2.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"47c8a2547b074aeafe8822904f577f826e23e977","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.2.1.tgz","fileCount":201,"integrity":"sha512-DGkbd26nucuwoyBr8t/CyXBpwue9CRkGUa8ZW8xN3AJ7QJz+UramSKeiVdiPFrhDj0ixu3CUfMiRcLCsS/pfMA==","signatures":[{"sig":"MEQCIF3fm5p8U3GaKOc9L/mtQ+a+C5j1rh5Qjo95SB6uEwfTAiBAyd4gOHTAsDymoA9RwrettkEuYvS5mIO1ohTqpl6nMQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":319426,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj19LeACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpfSw/9GHrO22jkGGzxNGUky+QJZfCNTqdBNJ57JG6R5auigzNB0Jh+\r\nBzwpFC2CVVn3Y45jcveJNncmPEyZxcfYYrWSnrwC5UtbFJqjX4FozjUjIKnS\r\nAdwbKEy9wo8cBCoPFmQHdd8pZIEhCyaY8DaWQc11XibeAPZl8/pLhJvXYWuJ\r\nX4C0kLaIYx0ACZ+kxwFeyXEDaLNGib5LspIJW9gDQJfbw69lGmP2f3xIu3SC\r\nFquqd7nJIvXx4CupCreY2nX+/dVbtArL9N9SoT4qammMVmP2cOYGSMhaLAVS\r\ns+LO7p71l2cn+vAJSNNAgjWR+yuS1FhqZFS+Tc+6TPy6VD7BczB0pctlWySs\r\na/TJx+Zn85iwDw9LWUs1TDnZ0ZiJaQ15yZQPx0832pwZhYfGjvd0qveVI9eC\r\nf7AEIv+bIqvRd5g4D/IS0dt/8MT4dNet/06h+rWh5Dd8O+5+at615XX6zOHX\r\nSNhFRjPksF7+WPLbGKZUzIlQltujmobYgy+3CaQJLTMylkhi8J3nDRdcE/fY\r\n/R0TwqCwYnBJAcqEnkUHb9f9ouUbqLvGEycgSCILeexmVhvg7d+Dy2uGtBTv\r\ndc4QDtMrch9dv2+yzN5qqu5VbpyWTshDbIqSKC5wYWLLTjYLkOE4EgTrkNeb\r\no0FlFr59Qe7RRxJIaBf2IqmJ32vVhGv+8mE=\r\n=e0sY\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"3d69185519359b5a7357ed8034d28b277f88bead","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.2.1_1675088605749_0.1897849696336933","host":"s3://npm-registry-packages"}},"1.2.2":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.2.2","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.2.2","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"eaa5ed02282e0035d17b44d90aefc55707b0e9a2","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.2.2.tgz","fileCount":201,"integrity":"sha512-uhnUD2eAlfpZ5pJ7f9Un7JaJkAHL2Q6TLULw1Ykb4/lZHIQ1PS53VeTyY0OZ9/06IpCn6su7VefTgipRSRn+HQ==","signatures":[{"sig":"MEYCIQDEi8UpoG/j7tCvxOKl5PRip2XrW1GfSEUBwR+hDiMSfQIhAK+6biHZe5GT7lVCc+Pd5xeGR02iLeYzO5UJofjD8MZ5","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":319481,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj192NACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpXpRAAmuaiSzGZfLc18GizekzsF8lj8keXV5uWuFpPvrDFUPZzoIHp\r\ng4jSAy33Dxz1O92n5O/5r2bUqdZunAFZ3JQihFq4YcRZQPdeG33XEJ/rr8qh\r\nrgA8vPhqFGbDMw3T5fd5j3vuWR1faePGvGMi2S3+9+dnUD5JuWmKmSHvdW2a\r\nVHwZboJmAZGRd5/jo2I+SfEaJKttqiTwBPNC3l6MF3Y8PD5l5i+4FVGhCnRa\r\nDQ3ridp3VxM5VnsQF2Izh+o8DHVJDSdo/HPPoZbTc9wXuGmXLIsNFq76tsIV\r\nQSwFdbdcW/WhbCRaRW1tN4Umd5gACryjFKU17hZPiCRjzbF+hzi2EUJ9P+T/\r\niCM+W+4MHy+DdfgoA1ohae6rlfCX9AyCrun/hYlmV55R/KcSMJg0pS5Ooqt8\r\nwENOMOX8VCSp4lsIU38bCpFyH+YZiPjP0YKtuwxqyhBZlVygZN/j6BBmeqxL\r\nfReC3qxsvaCNX55UXYmn7bWF8VTIya7Zs8Dw53JTiHHkYk5FS5imlEolrv/y\r\nRPzCbuqLScww35JKKkz+RDvrVMGmAMuq9yPUzkn5meUfSGoWzagkwNbA6g7D\r\nocZgWgxQLghlU4kIqrpwviLHFzNIqqLaqBf2OYW3nGSfdc7Fq9vdDHJMUDH6\r\nIXqcZyB6zRTe0kXH+YA324LLGfFZS8dDXoc=\r\n=xPiw\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"f91b4d268e12e5300dbf6a0a5f8571ccdb894a1a","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.2.2_1675091340901_0.8636097948438968","host":"s3://npm-registry-packages"}},"1.2.3":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.2.3","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.2.3","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"ce175f94e1bc644295d59684942b84a9eeccdee4","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.2.3.tgz","fileCount":201,"integrity":"sha512-YDEbSLRDnw4X+knGqCduz4/vS/yayUCpBsBAflwJdCJLwOaFQUWKau6dQCHftSlzoTdDP6Q2KAjsWifhzpIQZw==","signatures":[{"sig":"MEQCIEJ0+0qdqe53EcKYoqjMpLfWgdgkTXFgXLUlQVXBejL1AiAA6HlRkj9uJnaSHmnoPYV1K1J2nOoOk2fwoAeclzujhw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":319680,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj1+ISACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq01A//XGgQ4NS7F47EEkWLsS3b82m21iZ/XAtN0W5l2Ei8SeOoUkUb\r\n/FqI/FQWjD/U0ABLrVTNLMhTK90IkXAf2mIdUHfOJC2o9vSKm3nJRnj7ExRg\r\n8D6P83jpJpbo20mwTsRFUc1lkRHYOzPpALLeWaynYGngK93J5ByFgkKtFcD5\r\nZaVPM7uXV6SRhU/DKUw3XSX0GIJbRGpXyJpMi26z1yzwKfVABpi/7qbnpbmI\r\nzluBnZvdVlC9yI+XYU75WJGpmn7FMvcuHRk+Mq71+tyUHqI9Vgk8z8hECGdS\r\n6dAm69enyzRqAfq1+vm3YmKSbnOs1Dz4lBqvA/P6Gch+0vKXQkI2/wRKnFWN\r\nkIZ6R2Ci0UE7wR2shDPYWAD4mHo75gwdM5Ul/n4aZWNl+dZxwmBSfwOzBbTx\r\nzTB/TYmNdCsi6N70UzxocYyP09DFK6D349yzFgjM/k6PS+leIfAzav7NHj0v\r\nKaYfYW25vd8vfcEbIx6ex2lHpLgBhGNVNLS8S+azBDcgObWwwOiKYOe/GcF7\r\n69Fhr0po1vBayhLXlUxjptHWIL+NW2AJQpmAnnqqSMybMC88U4obSb26kDGq\r\n6fBmyNePeILqLCUL+lJF0yWypUrzO8JsJYFNMSx5ZxcSLDyqlarwldpHliWa\r\n986DmzK3tfioi60rim7xZklO6PHqzbSYXzg=\r\n=EKyl\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"29cdf6aa9bdee8ad1650940560168b66890717b1","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","start":"ts-node src/index.ts","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","start:dev":"ts-node src/index.ts --watch","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","start:prod":"node dist/index.js","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.2.3_1675092498148_0.46918984413239984","host":"s3://npm-registry-packages"}},"1.2.4":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.2.4","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.2.4","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"4c7838713eff20d965acdf4fe4fa55e0e2b34d1d","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.2.4.tgz","fileCount":201,"integrity":"sha512-LQpB/B3b5liA44uK3sg4EnSLWq/qPqzjZIbvOiLTF6WtSBC4+mW9x3BpVm60nVAWDhP42Lz8aNUazehLygvnfw==","signatures":[{"sig":"MEQCICQzoOlaGi1uSsBAx/s1PAZ9JIP2QqSK5ZNltTxn9xRgAiAYsvA40EUSaeCzQpJmMTwhuT6j8Kd/60WcDP1K36/D9A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":320068,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj259XACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrBqRAAhKx2Vpd53sTen/qRaXzf/J2ooHiPZzth153vdo5wepRMxhwJ\r\nVSneSutjQpcmPXtXT9STQ+oxbONLwpF+CpwFQs1tqne9nz1DKBFdC7uUp4gW\r\nKhdhwYHjN5aEOvwSWVnISpkOp7JelXQ7Xmi/r2FXpDD4OGkAzjZPkgGciSUB\r\nOFVP7Pi06yel0HC1rEzjOLua0uiq+/N2L8c2kx1XJJjpealdUlg5ilEvnv5B\r\ne0Cw6Mc5WxQOWmUW7GHmUcMfQ82q1KzxUMsWUKvhFEduFUbi0ZOxkmB4oIwe\r\nB+SlPONGm2zSM6E/RVxQshjbFeH898GipeIycOl4+Vo5BcQU74xkskyv5ftE\r\nK8EOFX4G///7WxDP8NNyyIt5+XoY4hJA5L00zdP56cMZBHhwqMhZu9xf2j/a\r\n9jNVwhnoQP3mskf1owqRs8IvhpjsrKu0945AWibsE823nf4oti4V0p5xczv8\r\n9fn2Kb8vL1FZl+vaU6w5dzboL+xfi2mfhATO21H5pKGFp5z0REr8u4oT5TfP\r\n89G19DBnGDTOfwQoDET4yVy7QfoYCWa0AREU9Dr+IuLOizaYSrHaLEkJLhwv\r\nWw/6ovHWJ0NeeBBBzAC+DbyqSiTMfmlp+d6mUX+Wb6054YybI0/YCa80/vDw\r\nf5q4R4tugIxKS1/GYW6oIDfepTIQ97qx6eo=\r\n=GD/1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"4b1e017c190b2a73e8c1d83137ab38e367e15a6e","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.2.4_1675337559116_0.9167691217070453","host":"s3://npm-registry-packages"}},"1.3.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.3.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.3.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"63801af8376e595d8c7b8e41054793ed0d3cfbe0","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.3.0.tgz","fileCount":198,"integrity":"sha512-MBKrIvWirGYpVCNr+m1JxFEsXYIjKTOiV+v6+dXgocypLnY/RmcLiuLQTIC71EtPebFPpxb28tkkP1lgdURBJA==","signatures":[{"sig":"MEUCIAfNnRGIEpUw+/wlmfvv/e+AB3vus/YkrGudSe3nLUc+AiEA03TgYyh4dbLk42J3YNneSp+ybxT35dw3ENVZvmb///s=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":319590,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6oRVACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqjaQ/9G5i81FqlD7YOZNVUj3HsUeSIHaFfzn3XQHeM5q5d4dUMUbar\r\nJ41rN4eIYra/cHlp2VR/NaEYq0BgJhsOYGayjp+fz/R9ee2a4r3dkns66TyY\r\n47aGuVNnguAZ6zfwt2hzWkA/p47sePx1fo2biWDRxjn6BQAg9YPqL3gQlh1L\r\nAzm3wmPWBOFe4Npe7k29EOUVlPkRJjLbxR03eOQNptld0ymaNZfk/oS/1qEi\r\n6utvs4C5VfVkUeBheN5UxLszkT4L1p+13L1WEw5BaiYeRWQIf8xUT7ywEa0n\r\nkomrtuU4dAkYO9t0RHqZ2gFzn7MufEwWvQXpHVjDiDT7scYein3jV3Vx6/ds\r\nW3itVJspMBOPXKOaNHKlWuUh8YCqjTJ7FtcahL36YMS/CCtvuoBDi8+qWE//\r\nFZJEjHLB1ulWh5NM06xAS3azORH36ffWjrrGSGFbrbCaG7HwFX5EcC+YxUdW\r\n20e3O5D/7kmxFnIi4r7HhA9Svaf1cNBzahJfXsmGk+pMoQ0elzVghlwdVNEr\r\nxOLrZChZvYcqH41cn9LpBcXpXcJQ7HyqQ4VrJl9IofK9TNzw0waBR8A9GqjB\r\naqH5/5V5KmGp+AWp7gzDcI/eDWR+16CsYD/PPgBoKLp7r33qL3nchH9brvxM\r\nH1DUESN0/ZZkA5m/uh3Qd1M7EVfiLISmbSE=\r\n=AfJU\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"d02bd157313b307fc93d0cfa88a959935e5ad7ad","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.3.0_1676313684925_0.9888842004137826","host":"s3://npm-registry-packages"}},"1.3.1-0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.3.1-0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.3.1-0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"72f59e7989557bbdc8d242fbcb939c324453b556","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.3.1-0.tgz","fileCount":201,"integrity":"sha512-esNFCEcBZhNluGJcLahFfGzgs+ZUwak3XCSkCKK1gS8IChbU1jjlnEhzHuau+XYyPNaDvDyli/7NuRYWu7+z1w==","signatures":[{"sig":"MEQCIAdQJm/Dw3cymEJ1L28fYLOFnxV93rez5M3Nu4EJ0+4oAiBFBpcvnNLegG8ARwYuPfLT8v4yy83Xun9PvCmG0jwH/A==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":321299,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6+EUACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqItg/+NUUTU/swBvzi5yyRVsuLeJeZAbSLqCBERm0N6JN/21t/nPU0\r\nKYPpdbP8fiTynuv/t03/eRuJA5m201hyJENRQ9O3YRPIytCv58rUtZxiIRco\r\npxmbONA+p2UdZBnfbcx82ULrO0ZnSvNX2gqUWQmDyktFTjHrI4KYoqblSvK0\r\n/VGSGnzi7a9RRRSbjzrNJj9+hXM56cIke2kQY6mh6hz0GwCCIXcGG8FgFpVu\r\nKS2jKlvpQtMOtUb5+ldx4ySkX/EcC87uLHBCEx2EwkT01YYz3JoJIqK1kfrC\r\ndRqoWKg+J5uV4QXrkdgqrukoNq/c6R0r2KdBO1VBEVtHnd6YVzj3Sux6UAsv\r\nN/4fcKq+QVbMv7Mhi2XcXkO0CcE6zSjTeNkzLi5OcXA6NVpSAG9VIeIkh+c1\r\n+bybhOA8oaAAIfqOtp/IpjZj7uLSwlLB2bVcOz8O2QCmc8XDKPidLy/ay/J3\r\ndepHOZrBF/fqJIWiXUhRJcpKjlDzrG7rrhLDWevD05oL6SbKZQKIcmt+jnGf\r\nt1vpZ0AceDYZqUwVWJ2f48SuL25FoG56fX6mNnm+uNMgFcxoJTRZ6JBCs9hG\r\nEdMUeRu5loyIjTKCykWpgQ1DEnV23BjG3NEI3c/N56XScmHdM/E0hqMke9Fg\r\nbygKxC7Hr+fjUEORq723T1Dvtz4Wf82r4V0=\r\n=wz4C\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"042f28f13c533e20e386391a6a1eecfb9ea2a73f","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.3.1-0_1676402964238_0.27524634566759776","host":"s3://npm-registry-packages"}},"1.3.1-1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.3.1-1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.3.1-1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"96aef7bd4358c5437c502ff78507ee9a62e8163d","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.3.1-1.tgz","fileCount":201,"integrity":"sha512-ibDob/QG46twUZG2kDTB6Fk9E0DPp8ShDm39mxK30fHnNwh4R5ixgQkwcMBKKfyVziNnIBc5lOAbcbnK5jZezA==","signatures":[{"sig":"MEYCIQC09fhT8TBngY5bhN/STyyYbpkZtyco0gxDc5u246tW0gIhAJI9l80CHMoo4gJQ2b5NnjiFB1bwAEMTsQwTY0vm24pN","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":325100,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj6/U5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmryTw/+JZPviK6X9hYr/1eqGECBRRtVMiuYYf185b9/mlYubZpt1HyR\r\niGOMCMSbRzk4ifnvTGi9xdsokmkBQXQAm9bhXJo15z1FPPfcpPnmxNl1mjkx\r\nMPoPlYKf9rzARkodpxl2IuLTqS4wzQu75nslrgAgI4ONZwhO20YHSUU5xDtA\r\nEwc0oVbOBfvAzgBUpuLp9ueqWMwbMoWjb97jMeCoNZpfXfjBQ+YS75XJoF5i\r\nPcbf6QxFSprFjrDJ2gFES05rRFcfcJihIz9/ghqKMXMGPYiLsOuk8yFVzzey\r\nEwPK4WzfQrt7w9z2FTWQfxMPW7XzGyZgY4qkANFjtgFD09jJMbwN39TeYvI5\r\n/tgvhw96GQZ6IN76nVrlPTGMQs6B3hM72gjO/FerEOJqAKtOawsBzy+hf45/\r\n0EsbyUvTbDbNRFeVjhQ9hdF61zNR0D4mPzCYAWBWtJnWa4E1ixlhp3kr4h6S\r\n5pFcvUxDh2hXIk24iuRWg9RxQ8QFPaaXvtjQtKhUTlsW9wa3d6itJziNYkCy\r\nTKcP680BpNnMqTehSm4a0ygjuC8QlkNJ9zy+I1+51qtTyniC2WH+6yslNfW+\r\nsdJotwwBC3I84K7s3VdZS6duFKANHJBRV002bLVIKy6UfVvWVFKlRaQVPPXm\r\nrRno6Gobmub6UH9zrPG4mGdVj2qWXVpA1vw=\r\n=Mr5A\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"c6acab4a6fb1f2e37cef365f5be596f603fdacea","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.3.1-1_1676408121671_0.26593447980993234","host":"s3://npm-registry-packages"}},"1.3.1-2":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.3.1-2","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.3.1-2","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"35a616fbd53c2dc0e1d8591f747bf0b8311f90d6","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.3.1-2.tgz","fileCount":201,"integrity":"sha512-4o9CEv1amtQb3TWJzpYec2gca3JGMiIpQSJYU2fxtqGNZiSGqWsJ5BunOdgsbhiDarIc4Yj0Q7GOxZwTMTlIaQ==","signatures":[{"sig":"MEUCIE6jQPliTWd7wGOdTX+dIBGXhjO//RXa+C8tfu/Ee2U5AiEAyS04onRW5+Wj3ar1+ReWNAhgcD1o09vORcBWI7nFTd8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":324374,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj7L/rACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq+3w/+K2LUlTepmQvhxg3Rcg7iWYqDRGWekzw+9Xr6r0dkwumqjugC\r\nR0fMILnHz1iPj+L4AC2zYX7qkK3n68KLu/93rOKcMB84XlK/NoQh4NHPJL/p\r\nUY3KfLjZEk8aeDGhaEu5tCTzxZfbqYn5dUdoxiUCOqXDVbZW0YiNBph/sWGM\r\nE47JqlNFpStBZNngAIMj8fZL6jX41PjSs5leV1wx/mv0f/DrZPwu6AZhRT5u\r\n/ccM2xcqM43YhGV5feqWJEpONfYeThmJlYMQ1P+3RLO9F0sZOaC2/aizLD3+\r\npbCuPTuAAEpDjvN8KY2Js8ZMy1fhdvYvn8vZYUIXD/lfx9Z7265Nvwa7i8WD\r\n2pKNaxmzFNwXP+49TCqLAWMRtt9X5QRvLgkkmPRM9aSWRNv+w3FrvhjWXOuk\r\nRiDq+ycn/NSzAXrR5l+hzRGjQuCLCNfLSY1HTpg3tLitK87cJnc1TtYaAeKX\r\nvKA5TDmFOfmRRpenY2FZ1/+fHzi6t+aoeIzLG5Xm6ejWMpgH4Hb6MhnElzdD\r\nwzkuJ0Rc/r1y8xdWPhKAGk7oqlaIfTNeY/5ZPL5u6dG35+awGgFPDdKh1QHS\r\n7hDHzjoIe5KU8ehQgucKkM87DIzSIqeg06Nu/SY05dlCzVvkGAcY5E5VbIWA\r\nwp7ohEpkcdN8cnU8F5U00NNlggFjwaOddBs=\r\n=nBZ1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"11d3c932d61607b8f04b562116f379232d1134ee","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"^3.3.8","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.3.1-2_1676460011411_0.05535615505104707","host":"s3://npm-registry-packages"}},"1.3.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.3.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.3.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"80752c284fef3bafb822df8ffbb124786e567624","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.3.1.tgz","fileCount":201,"integrity":"sha512-mXsPrH490VSAr+J2rsb6oAiEEAWl1rqajISBrf+F8xS7rjCqkRt/AefDujbOs+lgSM1BlXjrwl1p5klcCWBYKA==","signatures":[{"sig":"MEQCIAfnyXZckvXlQ7am5aOKsrri4V4IzglllcEzGiA6AVH0AiAyELZIQdnvXp9vv9TLQUZVx5QX+mVcioCcDADm97A9dg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":324371,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj7MTjACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmooxhAAlZ6foarfqtDjERFnC+OcdGgI7Kor31HzWfUBFIfX/LJ5LBeW\r\nEvk6OPwXZDQsOZKnpDkBH0ii3+PzH6xbmT8iTGAdclSw5DBJ0k2Nbj+J/bwl\r\nDqZSqQoaLNdgCM2vQHwYPDwpnZQWtxtc7Fn0azn68sB7LVx0tmzM5L72rdr5\r\nienHxlltIg9LcSPTnXIGRk5V7GXaj2V3H/Xh57RiyApHfqibNTHyuTWH1vjw\r\npegcNISaiATCEqTxQnbJ3MU5arjukUbsEdaaaOMZhrAc1TOuCmWXGGbXy7lN\r\nW4WWzCL4B+sUNqDndY3yaSmRp+9/HOio25/AJ5WtLd3OPX3jUW3K//GkOgbE\r\nFG62l+aYIPcYdt1vuG+OHdTSYD2+KDXJNC13J+fYsEBzeokiTxTStRZOfCSh\r\nunW4HOKyMP4FvLdhSkDSOtTExgZw3jm8py1lA4XIHHX2uJpzF37MwIoTpWHX\r\nzWwL5YvjpCjFDOGOkuJA0T3sCsvwhZWBRbC/mwUIwoHrBrNqZGO6njYMcHY5\r\nSN+l8+Q8rxgpJAuOTVW1HhY/y6SpDdTMd5fQ1RNAQb/lrkACOgcRU71Z1hjo\r\nBdoqQf6gG5RT+9wAiP0poIfO5Hpc6pfFqZpallW6s0OZ0+oX8x3SK2dWJyTh\r\n4046d9ZaUOgj9yE9jYXjMGFzFbsC9b8d6UE=\r\n=hp1U\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"3a1d92d16d0bf6c65e6805460be57b8fec16ab3e","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.0","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.3.1_1676461283275_0.12390444328834938","host":"s3://npm-registry-packages"}},"1.4.0-0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0-0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0-0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"2f301912fbbe1f8a250ea63fd1ff8f9d7dc61b7d","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0-0.tgz","fileCount":212,"integrity":"sha512-SrZMfJI0XdJmUfWllEaED60PWdjjJLMdA5hoGRwGzH1tJfUuU+1dSOjaG6DvmP7jSERGlnRd13RWsIddhBCLxg==","signatures":[{"sig":"MEYCIQDNtKKzuzmo+mvu2zaQyPQ7dv8ZUioUOsWYjDB5VHqZswIhAIy3tW3E35lfiBaOSF/Z/GHE+kpUJQZLeZbfCJB1aNip","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":340198,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj9591ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpvVg/9GuXIAHDlcHSsx7ARYCEq+OEL9+PtZ//Mg6vD8TSUqGHceG6r\r\nW6hsMdqLyi/DKys1lNgcK9K+wAjdVD3Z611cXBa8JfMd5rNcZnfmtlydebgU\r\nr8W9sVt5PezIfmfrKySAE1d99fff21cPviUnnnaDhNUX3iy+1xtTmXTYRa/2\r\nuhhisqT9zgxDnzUGYEd0IYjvaptBGc7XsEX8yNbQD2R2Htlwruvx3v/Bq4fy\r\n1x4sKiY+XsZ5r+G7HrJZEUj5cFp9jHfabE7n3bYmSTUnsNoQZvghiJkX3b0U\r\nq3JNdkcQAeWkQA7SYbRrS9kZBO8r3h+KdtuqgaamIDeFFA6TpSOnjOPgqILa\r\n95kk1R2twTNNPva7Xe9Z9JZyro3Hgn7nyT5q1IcEPlH8p9gDVKOi2ZlkmhNO\r\nPOZMxDYabGiLsdwizIMJZ6ZUnSC+8pUahKhfYZ0sQRWHJbau+Q8UZHAZeMg8\r\nclahfVa+r8PP0IOtn4Mq9KmkopzOPimgABaMZDxjiPE0RAjUSx7b8/kY6A83\r\nuusvttW3qNV2bG2e+cprapZKleM02zA5DptXsP2J23eEQgjIYUwROdNOPEn1\r\n5RLqdGLweZJoJSsBAYCoQysfgatFggh74tO99zy9I3G/wUCRA1CynnLmAqcm\r\n1VYaDkNAFv+z3xrDIpMJQXT11ZzR4fdPuEg=\r\n=UuQD\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"f942966e93b98ee5ce94a88c815bd7da6fe4f5cd","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0-0_1677172597191_0.3374760824634724","host":"s3://npm-registry-packages"}},"1.4.0-1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0-1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0-1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"f1be45cd6b7bd73bf153ede348a95fcba86ddd13","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0-1.tgz","fileCount":212,"integrity":"sha512-9Q0asukMaC7fq9YnyVfMmCvCRTLhnpyO1z4qcpHixhKil+DDo4BEIJIbkFqXiMhSVZFrENESae6Xz/aBkKxKMg==","signatures":[{"sig":"MEUCICx/oioZsfVmnev7QwOxpgLWlg9UFEZw4MednmPHUvsbAiEA+yxcalpPuAItmvV7RuBCcoo+hOk2Jsoi5Px9dmquJ1M=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":340963,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj96gtACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmppkg//QyRhg04luFhYe/Be2kSFpxoo4YPqbeCdeaZTY769x+Vu87ni\r\nw0Ov0YS8JdjgHdZzvMnOxKUgdqkARL2EfznpLOGDEiuFQzWfAKZcxAjwdGte\r\n1k6P5hvHboFRuHr7W8BPHSNV6mCqVx+Df64sSP6F2FVeNa6y+swpa1DoPttE\r\n1Xq0vUePiMHujH7ecwIQTjWHDiX9sl6HPQJjmlq+DKUvQJBwp7GzQxz/xCEZ\r\nJ3XTDk8h0y1u2jIY6OSpESOj5ZS0CgnCbpod/gtLXvnvkLun3dfFTLMMbl7F\r\nJS5KhCWNt8GZFN1v5nLD22tYv2ctTSqWxvgsQFCzuTezCgBZbVL498B4jchY\r\nz/N1ArAzZF1ZqOWx9U28y4zAUMUStqp1AC7/mgbvnRLq5OH8KYjHt5RnK5vh\r\nRwoaz3n9JtTUA3D9kh4zSUjyQ/d+nBV6+ozK/C25z17Yoxd2MOCpMPl/nRrf\r\n5F93sAP8NzWYo8MtXliUZl0Ywal0axkK9feptgD7S91vpdjF0IfLYFCYM6lt\r\noAuR9idlCleWxDq7OgtHZN6agRQv/GR+TU66uVyvlZjxyiNhu/tWpxzSArv8\r\nxnOrSmC6Rip+dHz1co4RuriRzrp8DOlB5VlmzymMhPvV3rcxry0I/3x4gCRv\r\n9YiEhLYxeogqiB4EuB2uYu9AYmwwYvt5rE8=\r\n=dUU1\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t},\n\tconfigs ? : LibConfig\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `controlAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcontrolAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Worfklow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"a9f8fb3ecf4f7fdd65d2b6c09398754ee2f298d5","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0-1_1677174829791_0.1947006070038475","host":"s3://npm-registry-packages"}},"1.4.0-2":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0-2","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0-2","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"33c2fa280ae09d94de999235d21174ddcc6b3cdd","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0-2.tgz","fileCount":212,"integrity":"sha512-GuExSaGQzL5ozN4HbvDO6l+7CglHM1STR7hbg7G/yJfLRllvhBFJH4AaQsVlWhLCktOKledcMSvs10bMzjm4Nw==","signatures":[{"sig":"MEQCIA+i+3Sq60DcQaLyXgNJl8whHv9U62oeu2kkwlAcHRUHAiBy6dctgspivoSTc68a/vfc4OGKM2+Tmw8A1cSwM365aw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":341596,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj98KRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrqSQ/9Hy+YEgulU6z7W4cwu3Bs3LHhqitUfgcs2ECcv73VgTA7IpiZ\r\nI+A9euS5vXd1SK2zl4o5/4mLn4RPSPUcv/C2utqy/8RmiGPZUIE+bO0ud1TI\r\nu0kT9QC60TZqU6FCEu7EEtcxdY9g8VxizAUVphVdmrKsO6fevduCNgz7fIQZ\r\nhHWcW5uMbS9ylVFbxNIs3qUSUDwXPHfhnPdYNlrFd44N5JcrGVvJRjkh6KZT\r\n5vdP6u9Ng3YaqsODpBTJCzECtUvn0f6KMMESpA1BEmI9tiJi0ftFB7JAJlhw\r\nevz8MPjc4KWeqe4Hl0Apl2oXJ8rnzIEjjFPVF2BAqgr430BLF4jeaVu03CGn\r\n7YlJ9pZdINyfrRC4yPNhnSr8xRUp3shfVDhXeUQzCX75lRO5KV3bK9HG5ZHu\r\nXVC7WcFJrnOS/iIIWLqt/zVQbTFZXDWfDNhlNavpiw56SgTXBZQXWykYFvkp\r\nfXM3ZVh3SwefC/gYzmdbKlzXBmDn0SQr96j/45USRUeTEdmU9RgYn/eprwKD\r\nV6clmClP17rarJJ0e3ZUyyWzLnItc2Gl2zw+5xQdIjWTSgwgxfhs6yGIQpu4\r\n+ah0QcB4dZGcU20qYVgYEGMKMP1e3xcfKpK3JycS4QglNwIPkyXxcFFiJuKF\r\ngYSHbENdwh6rL3Ot7t2UXhGOBRg7HcCW1ng=\r\n=EO61\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t},\n\tconfigs ? : LibConfig\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `controlAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcontrolAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Worfklow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"0466b599e6c63a6f2869463d897e1b30c318294c","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0-2_1677181585555_0.8648644109812591","host":"s3://npm-registry-packages"}},"1.4.0-3":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0-3","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0-3","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"27cc2b72c97adefd9b94dab1410254f5479ce5ec","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0-3.tgz","fileCount":212,"integrity":"sha512-npWQYtXQtNkvbSTRI0dEDVx7jsW3A1347Cqq6mJbkyFzQEVXdBQqaGKs9TBCO1yN7oWHsM8k+VQuVz5aAgPgMg==","signatures":[{"sig":"MEUCIQCV+y1Bc4lUOfWRgXAAVOxnGeCwQZ86zWDdh1P1opQo6gIgZQabMMeZSMpLn0XjcqgefIGZrrUW7YsxBxjEJH60NP8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":341187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj98XGACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoZRhAAgkYfYP2txwSkdsDyiFtYS5hFnEUzStgTGiKeDsh0N6a3WxiZ\r\n3cQHANi1QXSCPq0V43Oo0n5I9ieGCqyPRnKF4dXG7TL36nrD1arLBtQNtOkb\r\nUAlXRACQzgbk4t1RuEEciaavTeP73bhbzqexhFwUcE8ohelLTFBfUNC/IYD9\r\ndTI8MlDD9KtcFGEr7t0XOS6d8fPL/s4RMybJghk2vLmtdBvNoDNgtd1ZV8z/\r\n9LlCWGbe1bmSTrR2vMh+yCsbWQuwpd3tytpe9b0NIlrn6qcFR63H1UjWdHlM\r\nAx7R91a48PYgV/ofM7Mp36UXxJugLDshAhHA6O9WdD0MNw+6V8MUZ3aFc336\r\nkUzZ8xpti493LH/ezWnNSsXIc1yyxMSXnsAl5ceBNHSLpzRjVFvqcwYCQRxF\r\nIguTdisVB4WhhwbEB/W4ektVdZ+ITe89Wc08zBub3RIhEG4bXM4ImtM9KOfI\r\nkJJQyhkyjxuqWFRYv6i+davjOzO8BROzhCbnPyTb9Jc1pzpSqNHz0U1zphd7\r\np15Mx3agfaAWCOQCd8tXJZ6auNkW9a/E3dlvSNhB7baRvlVIjfZTXKUxjkQE\r\nxV+yOaOVp1j4XI7Kb48VviLDdcHI4uE0iHrO40VIfWZjr8CpQOO4HaaK4z0P\r\n45+ih1Oh94BMQcmwxETBeIqiMBTqK4QwoPY=\r\n=kEsg\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t},\n\tconfigs ? : LibConfig\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `controlAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcontrolAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Worfklow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"a605736692947fa0ed1383d84055fa67dc75a4ba","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"ALLOW_CONFIG_MUTATIONS=true NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0-3_1677182405819_0.38367500927643805","host":"s3://npm-registry-packages"}},"1.4.0-6":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0-6","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0-6","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"d528eaf3f7c4ef93d0ccba746385bf49892acf9e","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0-6.tgz","fileCount":212,"integrity":"sha512-xuMVg5U2KCEcnx5mGsoRSe9yuPUE5aA8vtZzTC31Yud0AKa8KeMFEhacExF2M5Y2n6AoyjPyBEibeXy77SQQIA==","signatures":[{"sig":"MEYCIQCd/VZkVLeqiPC98gUm7JvwX/2P9w+7zZlnHitnvM06QgIhAPSZP2XA+1CB3YRgxkO/8ZTdVUdOV4l4R+eMyS8Dl8ba","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":341167,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj/KTvACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqK7w/9GwxDT12M2GCuFH86lpK+tNXKC9rUleiPgLkqzhU51Qcc0i9t\r\nSOxEy/l83IhXBMws5z9F0iuV1kj9i0LLj+YR+L4nig/pRT1BWZzB+lRaAOfJ\r\nYMN6KiXKhkk3PHL+UvDKFjdc4k2vPn9RcKOgsiDruk4nOHOg2b8razj4UYXV\r\n6sLotshOZjnX7UqAlEGaJN8X4niVCE4UaYCYQO5bjodHPRui+AAjB3QHTeyd\r\nv9DEjpwztVHi29YBNauIS9scNX2LVji9bS2antMQ0UtXwBJB+S0tT7E5lKRL\r\nQ3f6vnUT2rQLe7rQBTzX+QBCjbvuhAF0Nt9EcHauozk7D7iTdQXG5gTalb+z\r\nLUAcOvKPykyx3z33NlneUimK7N7A4cAdrB97NVs3qq3YnMmBCKc9iOs3Z1SY\r\ni7DfZxyEFqwnQHXSZXKq6u+yeoOpr/g0hXfthWKtB1X786OaAeEiPQnYw7iG\r\n5Of+QTLLo9dxuKhpz6XnJlzM2QEV/ROiLeu4n1u7tIua1D11aj2D0Np12F+a\r\n08y9zj0YNcjHwNHv1EMRZ/iOhiVYzCB3XXXFPtQXYSvWaZSvJOCmN1MKPxjq\r\nVI2X5WfavsVhnOtIb9JWTHZ2k7C73cmPA3NDh/ytd6owghcL+Y24AMaSq1sB\r\nKGH+n8U092omncn1GBcVfLalFo9yfpylm7E=\r\n=EXka\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t},\n\tconfigs ? : LibConfig\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `checkAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcheckAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Worfklow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"291d99cb8bc88cbbacda35ff6c89187608ae758a","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.33.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0-6_1677501679458_0.706358745297063","host":"s3://npm-registry-packages"}},"1.4.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"be0e60ab03d4d3331175083b4adf36d152534868","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.0.tgz","fileCount":212,"integrity":"sha512-VbjhqiJf4cf+JsbH3pFBJdK1+fAA2QezjVm2Ov+xlPkPSPIZX0fWDaLfTcy70GncuxtUZrB+PMXqX8yt69Pp1A==","signatures":[{"sig":"MEQCIHR8IQBDAUfdQnmZ5aYJNi/LsU5t1XyAP8WNuxU2ieshAiAEwMUovXLt+0JOZocD9VDxmdeRZTRRlFl65GAw8XXSEg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":341268,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj/28JACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpPUA//dHhS67QA5eV0SwvGCxpwEF4kiRd2+0lW11PoMaIjF1RFZQkh\r\nW9pugzv7iBsndSh6eLcKH/kLURollU98VQzXogdVDokVGNzNmRd9atNVA/nm\r\nvNZLNv8Hm3qxAwN7WH0XXRL82RppqIHfjYU8z91cH+7gP4NInIg+nLf1VeQC\r\nrj8TBbkHWb4/LgLZVB8jMaoS8uZ3oD7t7fMq+qHQGMhZ78GCvRYlmn3+qjph\r\nrj52tGCkHsozIfyJXVtES+2xeYFumjLDA7z4G2XxnuhCY5N4alTQ0GLzwMyV\r\n/CTUbM/BG84ZNPeBOt/o39t8HQAUkFGw5QddsNGxnPkFcQAtbugN7ZyCV4IA\r\n3HOqZqccjpe181hwjmb/KX3plaZCMEvsv/7+OQYut0d7balB76gd5PfsmEVC\r\ngJCVEwesDWWVHVdkrC6rgMjnfk4RS1JPAsJsX5uxx2uFbgEtzIP75HqkYSwI\r\nR81WvBallZhdiqlgz9CfwqjZNoh9wZftADdfcT68VYkkbdfdPU0fbc0KVLDj\r\nV1VM1xsMGvHtNJ0VUS//LY3b0nGc+AJofExWA4XZEvWdKRe7xbzd/9nnO4dD\r\nL739N0t8SUHXSh9TNooEWidXBIlpLICvn/OfQcnfsSjtuIrW7XXuSKtmJXrV\r\nlMCHYpQY5VxWLezIEwjOf7s8qFoO+iEb8VM=\r\n=CH/N\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"d16bda4b9d8cb0924237dd2e5bb7943c0a31dc5b","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.9","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.35.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.0_1677684489114_0.43263061213010134","host":"s3://npm-registry-packages"}},"1.4.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"680e7b3795de313c35f03e36ce7f8a4e8ecc33e3","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.1.tgz","fileCount":212,"integrity":"sha512-hfu7S328unRSuKtmLgPU8aZ8toiZtyYx5NmZZAJa2PTvcX891KFoWJAWKwK+6dbFizgJ9PANqpln7XOtyJwS/g==","signatures":[{"sig":"MEQCICvQwEeLHyxzJXLAeSOp3OqQqzd6or8wcR6gP3sn4XdxAiAoRBw89qptip5iL7kpi9wj0hFFdTFq1nzAJzCCGuM1iw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":342845,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkCHmKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmofBhAAhOHC89K0vuq/dBGGHdj0mFffMKjsoKr8zstjuUEJDY3nP54W\r\nveSMM0RoOI/8Tr9yYph8MG6kVvDCMhrScH1PJjoWn5vL0eO2LSWpjrlLDjyZ\r\n6xb4x/xQOFs0OYndSWyHR5LxYeMGuGSC9ylCwbOE3T9zGLnwF3QqDxkfEhk9\r\nIPjzx07V2MtNvrtc6RBc7OhntR+NMdAmlkSfLGCSCZ8O09ePyUnwcARxF81i\r\n80D+W3K3woaxlipa4v24Rs3h858a7N5UbNFp0P/VbY++C7LlY2vxFr4aTJNI\r\n7Aoj46Hz+beHdLh6Xd0gnTx/qKG6U0FwFfh3u7JC7WHs1H2zNT+ic263Hw9y\r\n0FXe7hmfTeIIDRnA4+eaGd695IC4bMO4czIx0iDrQ47zblUdzf2ofE/VHTqn\r\nlMZu01lMctnkx6zGL2ZmQNIof0uS5ra65AvH6S/EUR/Jp7/kP+tKbDBswXQa\r\nizl8EhSBedvjnBKu7P3cqjz514lviYPzgiFvf2o9c+bFNN17cluu+k7Lw60Z\r\nsn8GfZqOp5lkY46FkdrE8g4emWHMoMj52993KiFoyo18i3t/AXlhCGq+BIQK\r\ncoTkABWYv120YUtMDexnPL0DzpkJIpA8yRxcGMqzbFGrTLtdGwX4a3IwQTEO\r\nohGGciH3tQagReJrlNeKqbPsyx3LeESL0rg=\r\n=j2Bq\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"c6035fc88c877d54aeb6b735df416880dfe9b301","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.9","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.35.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.1_1678277002156_0.11434877028388124","host":"s3://npm-registry-packages"}},"1.4.2":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.4.2","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.4.2","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"c000d7d4e0b099ac93929e77e5573bbe1e614399","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.4.2.tgz","fileCount":215,"integrity":"sha512-GIZ3gwtudt9v/cUtm8l4ZzvX76Dzl+XaF7TzuTrd+Rt9hp7v12PPEwSoGAjo4I5BqA13oCu/gzhKkm2FeZlcrw==","signatures":[{"sig":"MEUCIFminLGfwHzEJObPhnb4mqywNRkQNYOVJYZuoUbVpIPPAiEA/+ovZTae6Kj0RT5kGjkJd/UW/O08AKtv7xG7I5AZuLM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":342790,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkC0xrACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrc4RAAj+iL9TdOAfUWd0+xLtqIU7n59rgfC83epcZOEr8TMaebyHEn\r\nZRZBqkcpE3R56KO48Rbm9qLxZDbxH/VvHhABJdM0nHzH0DuNRrp6ogoBYNB3\r\njqbhvrtMD0lwoqMUKKKbP7HshILE+oarudbE4s63uU8jL8qjdafRdigejbKJ\r\nvECZtTOpDEXmHToJz0/DeTh1AMAuDFXz/Wb64tzHtIvnhXWn3ezzkCcrC5WE\r\n0GEB4g/XKvj51jxLjW7PSiRJvmDqo2r/9R6EmrZ6zjsuBdOFSJE2S2U34yvO\r\nkBvUIf8rPcFv45jyQjzf4a/iXvKzgF6SIYjJ8WVcNJQLi5FHBy7riojsHEtz\r\nrydC3LqMBCX14BnSMFVZY5ikABxfNrs2CKZ2fG0qzv2at7NCKUzITJtQ6Mjs\r\nbNH3YfUpsdwghhq0U5bFHLvsCzQ+9PGKB+yH0gZ1piZDmynmLBSENKmgfk2p\r\nhl95px0VPmly1YSFrwQu0R9vcLtnoM724GE0wtnojrMl/AA+wy/Mvi4/MQ7/\r\n4gvTEPOrbHcUpedpkMft8L6evxuThuMLMES6T3rt/mUthhs4lp23p9jtIKNY\r\ntYoF+4uRmYvGFJBsavNHb8bUzr3NtqFYrashDu9jlPtt0Xa72Dfu5xEtJPjJ\r\nAkJEHcJqgTOfCTrD2zG0ld84yEtUq7vD8Wk=\r\n=Svr4\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"47816bec69dbca192e0cf99627c9ee8ae87bf707","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.3","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.19.1","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.9","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.35.0","ts-node":"^10.9.1","passport":"^0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"^1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.4.2_1678462058987_0.9534780248418617","host":"s3://npm-registry-packages"}},"1.5.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.5.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.5.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"eb297483f40fba6fdb7e158c6642d6d14e49ad9b","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.5.0.tgz","fileCount":212,"integrity":"sha512-rhZWfZuvdwEigeB1pV+OUly51ZO/63Qk9fhJTts5KSouNZFuzR/BiESXmzMfN/1jgdRc8EuIDQWqt+0bUxdxkw==","signatures":[{"sig":"MEUCIDl2saMBHuJOGoKZwH0L0nC7zNgD72GdBrOIVaX/n1sLAiEAoqTp7+zbwtanG4TNMrV+ujVLPpPb9POU4GH+z9Z6Oyo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":341734,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkNnMsACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo0uQ//YOR8PlGu4LU9UF8XH9/BZDCqxH+Xctp1AZ5qLp84TRvC8kik\r\nwNg9iNOxr6zcEuCytL4Xo8+sS3Gv4sH4U1PpsJ5Qf9se0myMV7P6dd3l1TC5\r\nQmNTFkdu+og6qQsD+BVKGL7rSu/HILZmgm5U6t9q2tcA4hdXrHTUj5BSCx3s\r\nd8FtCg2IHKLPVoRMadPZZ7l6bLRF7MCu+oZJfgZ41Ew8mNK7cG+XVcmTICWr\r\nNS1PF8XuFrrZw+wTHpUDrimhDDOLNA2A5yMgQTJ52iOH2quLinVYcn+yco0h\r\nEE5nVZwPFHzNxXbA6j3P8KMVniLAxma7TyJqDzmSE2joZYBWogi0VZ1BR+Sq\r\njc901cpNUMZdFSib+qYmOfzgUUwIM5/VNqyjsuSl4gN5tciQ2A2sDi50MO3c\r\nkwe5pxbvr+0b++DA9c0QTXTqJy4Q4qVhDIqWtZoZFsHRRc9mywH2YgyMajJU\r\nBioQfl244+MZQbtnwlMDvDTFn1B3DhVpXxTuxZ+oUmIwaV7DRQ3SCb5MVf0z\r\n0G5ch7zqxkSgajcti5t3D1dfmbNjTTzb24dCCXLztbufkbcZR3a2aZT2vmTZ\r\nmpvW3rchbJgREt9y84z3Ju7k9qks/4UF0czpvVARjtCtvsOQDQbMRXEeoHEz\r\naRUC7ghQWSsdi4+KzvBetQThpBjIgj9ybgU=\r\n=3P+o\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"64e4429b338e0444c8a8d73a59d7d61924bd0d90","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.5.0_1681290027845_0.4973387537238043","host":"s3://npm-registry-packages"}},"1.5.1-0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.5.1-0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.5.1-0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"36e2678b081652e614fc7877c06f42c5316ad51d","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.5.1-0.tgz","fileCount":215,"integrity":"sha512-jUg8fZoGPFZbH8Nnt9FT6Q53lJo5xuSRaF4RzPmaXBUSc/hzGj0wGcy6xG88JVVwZcAjkjN2okMe4f8nTPeGcw==","signatures":[{"sig":"MEUCIQCA8V3NSWaI+wtX6w+KNsdbT79rY0sB6coVcxjlItGvmgIgPke9BQuNRawHSdV95HWOuDIWL//3/C9JMZt07/QyQVU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":342549,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkNrZTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpWjg//aJu9INijfwSEy4svkkS3jhmqT6NzUzuaODgq/iGYZGFzlsIl\r\nv1rjG0u1qzMV4jpTIrLp/bcdtl9q3jdFzT7ZoqNDi/EYwdv5atuIstbJOiZC\r\ndMbKBd8LgU8irCt1jJ79e32EM23zpHVSDuU6Vpr4f2JUE2Ip7Vird4NBFHOi\r\nfFS+TAhsKNKKFc2c06JdnEq7vyU/fcl6CewIjIMzwwJ0NnkiMilZVjnpXGUE\r\ngqj1tYwzQ/5791eaTDrdvboT/PfRDHobLPi2U9Zq0qSHhXpalNk2Adeimze/\r\nstIbUQGHryT4L4xl96JJeADmp32la1OT3FghvV5cvqVR495h+S5fgRj5iwLw\r\nVRUHwtXJJI9bQqUlSUni/otdQiJ0vjXTVri77oaBkGhjxnL/87XBwxtGVUhO\r\nNod5Vtvv2fQhLxukwA3flXvZ80mnq1IVPaYDMUaZF8DnSLD2dunRVprizzID\r\nibANy8qHzj50c6joF4+zgczm26RFmKA/BIdx57ri7EJVAY+Ot9cr/OHz+CUq\r\n1XRw3lzvRfkEzZgTDEZl0Qg2vCT4mj22UMncBlzjlnWU2iuU9zgMrBNL0RP/\r\n78m3fkWEZnrXLf+huoLGB09cmeVdBOC45c4RYLOssboMQeDcfXzCp9jfcfaQ\r\n1E5gfAzRTe/MaJQeBjs7TN1EDCcpRhzcVSc=\r\n=0ZKN\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t}\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `checkAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcheckAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Workflow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"cd4b21fa4dff207e9fb90bc2bf822cce2b9755d6","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"NODE_ENV=test JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"NODE_ENV=test JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"NODE_ENV=test i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","rewiremock":"^3.14.5","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.5.1-0_1681307219644_0.9219967948852528","host":"s3://npm-registry-packages"}},"1.5.1-1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.5.1-1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.5.1-1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"c53532bde2576edeb04bf4445e9c18e2372df167","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.5.1-1.tgz","fileCount":212,"integrity":"sha512-j2zRNsdKkNNDAME1LHqzYz8JZ9kdAMXqXZIJLPPvdHFjyYUlYXxINo/ZCTf4syg3kR8klbEZcyZ2b4iwzJF1Sw==","signatures":[{"sig":"MEUCIQDAHR2WcvuzMaaMxwfyjw4fgY6Ky0oK8jO+bA9uNMl3jgIgWmnNVPfo5bhn31/qqECkviXKqQ4I718eqZH2FsupHio=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":336997,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkOCh7ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpD2Q//cDeOpepvZ3FeJHlCbhYo6m3Shsi0nmkeQZciknDyIUQFRRxn\r\n7PgQyHfj6d1fquL3XyvKeUArG/iBQbe80xRVz7bre3gbSSRFFMkABtTJc2KN\r\nICN4LSuGt6VHJ4PiDw3u/zB3aapK7Sy2IYxMcW5UDmP+AkKkqeftNY6GIGvI\r\noqDM6dXhZUdF5Z7/AEcJjSGpQcs5PWdZY3SfqwSPJyNr4GagMbGQ0fncj+vg\r\nSryWmqNfOOYFVUR1p8y2bUlFO1VDpcRYBjDVjQVRARM6VKYvcmnS8tlQWnyV\r\nn0ibpDe1NvevcgI7Oz7l99zXNRLR8eT9KPH4iqAd5ZmyYxvShS2zw2LwPVg+\r\ntyU36rJqH12HdRTSiNKn7vG5z1Gw1/tYNQgxqej7a5DHsopWfH4I+tRiHpAz\r\nJopSdT62x5WA7hG1fHkKel3HkY1uJWBEZGpywvQLhCrZU5qHWH4qBbN2weAD\r\n2S8dpHy0C91lmORuCWFnzQbIuaeAGYWJDbo3itqC5d7fM0yKdT8WslfMwzmJ\r\nQgjY8Uj2xWIaqyYtGHZntIROklxazx4LIzW9ioCyA0mZ5Ps0ELwZbmWERfrR\r\nenWu8kwNzk1R4Ma0i+8CSFqWRRu1ddQmQVU2wnuu/odd3rhSdxZfHH4unEmh\r\niltyx3J5vMVQ5TndrbUu8Tfo81FlHZMTiOc=\r\n=C/3R\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t}\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `checkAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcheckAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Workflow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"c1bba50b5cca23373f3bb469e1d07abd6d6a51b9","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.5.1-1_1681401979520_0.3237364515419925","host":"s3://npm-registry-packages"}},"1.5.1-2":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.5.1-2","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.5.1-2","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"4085b107adb1fad97e9240767fe49c078e49856c","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.5.1-2.tgz","fileCount":212,"integrity":"sha512-NV0OdJJAYfQr0uq9Nz6iJ1GukhUCgN6RjhYyXMMYXl9FAteGG0VS6H21uWoBAwJd+G+Cvb+PU13FoxIhpYGknQ==","signatures":[{"sig":"MEUCIQD99pdSNPYhqRcYbrFkXOVcSTOm2nKxyXR8KXPjySNIWQIgArIXcZNrQiyRScD/nwrS4DSUv2nGlWnYrEutOlbWJmM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":336451,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkQUkWACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmrz/hAAje800NxGYkyN3DxXikEEhNAA+Ln6DJl2i5zALM9v1gQfyGN1\r\nt3y+/HAowvkcGDXpUksPrl8jJ+TQDhatEylGYEFikuoM/8ca6sO0fmty/zNY\r\naeVgkV+PhiRdx70scKuM/WZ22xkAiFQDHzCte9//+JHSUd2suW0hPDtzZf9a\r\ne2CWSDkFDEgVzxtmGfgPYxsiLzrmsQZ4wh4sr5GQK01AeQVx9S1r6MKNFkXk\r\n8h3GbZQtWdHanJ8LtWUqzwHQBzV3aN2iOpV/kGbkg8yE62bW005ZfKVPeJOr\r\nYMTUnYPORZlmuKGxMZAod0qNS7/xUQYV4eWYzOne8Hm0Voxg1g7Us0BF0lUm\r\n4Zu01SChKn1wajZ8SkcZ9i6392bTgIKylHj/p3Dwy9xcYzYjb5x9Bm80c5Fi\r\nQ6TG5XGibAPggR/VJ2SOsTJRPYZ0XorZ9N08/91TyrUDezuMujVFUK8vDC4Q\r\nQDbJOYn/aWEDtc4HsFtc+UQHNsRx3Pbb8ca2eAz/RQma6cxZYvYu0pSqlASv\r\nlgOFFbzP6t2xQJuXNcc3hNYI+6K4qOLZBhb/Ibgcp3+xwNPPhHEOj4bjewwG\r\nknNN5EbmgJZkR3RAskDLIebS0dmUPbexgT5bJA72lNHjVWhPouKQ+5eGVEdF\r\ndHCRTPbD9jWPXthRBAXJOunOYdB0Zj4843M=\r\n=ovUl\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t}\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.endpoint)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.endpoint)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `checkAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcheckAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\n- [`Logout.endpoint`](./src/logout/endpoint.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/endpoint.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/endpoint.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/endpoint.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Workflow\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/workflow.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/workflow.ts)\n- [`PasswordReset.workflow`](src/passwordReset/workflow.ts)\n- [`RefreshToken.workflow`](src/refreshToken/workflow.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","gitHead":"7212053290637168048386af75a5779bdea14ddc","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.5.1-2_1682000150250_0.38506895260392326","host":"s3://npm-registry-packages"}},"1.6.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.6.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.6.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"8bf37447f23bf49bc98bb88c8b0b0f6eb36537bc","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.6.0.tgz","fileCount":212,"integrity":"sha512-D34x5Rdmj2Dkv7U9ILxGIxMzCjCGJ62vookHgyUi3F7U+AisT9JuLQQlG6n+IgVJHhqA2F7V04Qs1D8o+XXL1A==","signatures":[{"sig":"MEYCIQDnuZ1Rx0GF/7SDEwgMJKFLH3f2b8Qg/4VyctO4+fTkgwIhANgKPJc7o3FztL4TNg5CsNF8iJwhUcI1qtKiux56YRoo","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":336449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkQUsKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqvIg/+PmMoW2uslRv47lMXdreoc3JlEsfxwmh3lA7o7iprqN5C/B+J\r\ntpRKHKxBGMh1LbSxpWhjQdeBgG51p02MTyTU/hXFp3IAc45iV/+hgcivahbP\r\nuHgeFfH0lr+/VkApD6kFN/oa8EAa90mPtHD/bpVRH+fP7OxyMSKOsYl2BJh5\r\nA5GKmRvDJLOHaeMIC14Y/7x1rxCmiWblv3+4HM/NCTF4AR457ADIWsblJ/Y/\r\nmHwmZ7npztJ8FYFIACQFe5kTYyBLJpi0zAmYvptdjFA4Ny3Ste/fBeg0+9HP\r\n5rWboUrURdgPTQShkSzHdwkotdQB2kRknybKUFIKhdw4fvWgZMWNhS6JkLox\r\nWYHPD8vN0rYT8RdAPSdP7fy3YYOgv/jZpq3glcI2TmsN4LhtICHfZKy9kM7Q\r\nOSUn+EyK5Rd09ERk27bZxA4TwMflfEDgNgQE2OP7I0JCTGbmBUWVCSiaklnO\r\n0yrQ2g1mI4nR6atrbbb2sHgx2dAXR7GD86SUHDlbSM75ALNE3oTwcG7/d3I2\r\n5C9x/3rQxpAPMPb6WzWHcX5OkX1sLsiCYBn0kZQ4Gv7COzC+lOQEp7XVirdm\r\ng+iIrx7myAAmVfGlQ8X2qGYFaiMO7OquF96JKxEXdtjJoSBaE1FXBawdg/Pn\r\nS8NjqmGFbQClKmwbHxaXNgSYdrjkx7qUYvE=\r\n=hfae\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"3a151f60096e8dc6dd44742dc55cec828e024cd4","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.6.0_1682000650425_0.08437505771806708","host":"s3://npm-registry-packages"}},"1.6.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.6.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.6.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"c42d53ba2e56c5f0b9f77241c33789f20f61b105","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.6.1.tgz","fileCount":215,"integrity":"sha512-q/OzujhlZyEJ9pW8PVwHEgxxWTLtOBlhAOEllVN6bJnGKzoPu17mN3EveqU7+WCZWFN2ZySFtoaPG0A66JpS1Q==","signatures":[{"sig":"MEQCIAqOqJsqFRT7UaqmgCPQjORVptXg9WpynDAXx4rGqOAHAiAE7apmOjxe4NZUeKuGE7Y6TmR3kVX4Poh6H66Xj1U8wA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":338584,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkQqU5ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpSLA/9EN11LVIabaCKjgHTbCGis4bBNcHb/7kxLi2hqlI/nTKS1NWh\r\ntA1F9CbnI4sxPeGtNzNwiYnV2TvxKXyofkwB4l8fOfLrktQRbs27KY8pmLQf\r\n8/TfARZ0FZgEiwq2jSGhN3DFLV4RkCMGeH6HAnexgFGL30x0Gc62aN7Bf+h0\r\nzGtJXcXMl0YUyCpHZZq7E2y3P1KB7t/BSRwreO1jdSjFdfvGsaOlsMnqY0ew\r\nEvdWCPDe+3wYBXANs1Ug/0jJi2pBWy55VfzBb1NbDW1gHU4f1ih8+zNJa78t\r\nQYQ7qR4xlf+hiXscxT07xkmkdKZvoLdlWtQT948C0ESzDlyVwYPTTx3c56Le\r\nxgI0+0SOwxpcPb58kEZ2Lgh6TD9n6XogSc+bKuD+blOFNoV0Mmw4T8nHhQ+O\r\n2k3fhgkTqnXiP1qNORKf0GMPVlDctW3QFcrgskNeUt7TeJdpia4RckNWAXCf\r\nRkKn/CrFCWuM8gcH0hrZ3pSnJy/u1hndVbxE2P6Sg6BlqnHucF9WljPrZ/as\r\nLwpSpoHgcii+83n3vnG4fs8me0Zrm0QxgStDHjNL2yoqZQj/l8UJ3LDGNtPv\r\nki8SzgXJ2jxfHlbOg7bFPTO+yWb25xI1skr2VwrPNjd/ZFphCsL7H0DlOodq\r\nqz+c+iBC07S2tV6IhjCr52VppaV5wevwRcA=\r\n=QbBX\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"4c967134a7768fd8b4482edc8983b535dcb6e58b","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"^17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"^17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.6.1_1682089273549_0.7557582490471015","host":"s3://npm-registry-packages"}},"1.7.0":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.7.0","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.7.0","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"ab07c50480f2375224525dd9a2c8bcc3f2e717d9","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.7.0.tgz","fileCount":215,"integrity":"sha512-fZSCGJ+06c45v4WEVtdgxQv6GCQp5Jy5nxsb8BOvBwVHnx+jsjcosHRQiefk52j6xCifkC1MSHQCQrxP4TnfUA==","signatures":[{"sig":"MEUCIQDs1kEi+M97EuMmIrPdAI7hc8Ur7b7ZSqVOYQ9On+78BQIgQzl31z1qIZLfBc3P43LbNmL3xStTSGOwzOfjioiUpaA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":339621},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"50cd9e93894cee8f16863e914ad942820e28464e","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"17.7.0","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^18.11.18","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.7.0_1685099587545_0.6521850150610016","host":"s3://npm-registry-packages"}},"1.7.1":{"name":"@goodrequest/passport-jwt-wrapper","version":"1.7.1","keywords":[],"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","_id":"@goodrequest/passport-jwt-wrapper@1.7.1","maintainers":[{"name":"logingoodrequest","email":"login@goodrequest.com"},{"name":"lubomirigonda","email":"lubomir.igonda@goodrequest.com"}],"homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"dist":{"shasum":"a335250b75e6d1a71e48ded457c1678330b5d1f6","tarball":"https://registry.npmjs.org/@goodrequest/passport-jwt-wrapper/-/passport-jwt-wrapper-1.7.1.tgz","fileCount":215,"integrity":"sha512-8KJH/VjDzEUqYAwMDyr4THOjWabCGSuGnloH0iDrxidl6FWpgMHjB8bRU3Z5KdzRu9Nfq4lHUgeDSXe/95vLOA==","signatures":[{"sig":"MEUCIQCtJjGil9DrzRyk/8u5fSEKWxNZe3E1v6AFi8qvW/g1/wIgX6DdPwsJneJv4EcOsMZp/k5P3v5mYUHYYDB6BCz2qKA=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":339619},"main":"dist/src/index.js","types":"dist/src/index.d.ts","gitHead":"0ff1c08ed71717e23fba7a274a86453acd399bb5","scripts":{"lint":"eslint src tests --color --ext .js --ext .ts","test":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\"","build":"tsc","lint:fix":"eslint src tests --color --ext .js --ext .ts --fix","prebuild":"rm -rf dist","lint:watch":"npm run lint -- --watch  --ext .js --ext .ts","test:debug":"JWT_SECRET=somerandomsecret ts-mocha --config \"./.mocharc.js\" --inspect","test:coverage":"JWT_SECRET=somerandomsecret nyc --reporter=lcov --temp-dir=\"./temp/.nyc_output\" ts-mocha --config \"./.mocharc.js\" --timeout=100000","translate:scan":"i18next-scanner 'src/**/*.ts'"},"_npmUser":{"name":"logingoodrequest","email":"login@goodrequest.com"},"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"_npmVersion":"8.19.4","description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","directories":{},"_nodeVersion":"16.20.0","dependencies":{"ms":"^2.1.3","joi":"17.9.2","uuid":"^9.0.0","bcrypt":"^5.1.0","config":"3.3.7","express":"^4.18.2","i18next":"^22.4.9","deep-extend":"^0.6.0","jsonwebtoken":"^9.0.0","passport-jwt":"^4.0.1","passport-local":"^1.0.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.1.0","chai":"^4.3.7","mocha":"^10.2.0","eslint":"8.37.0","ts-node":"^10.9.1","passport":"0.6.0","prettier":"^2.8.3","ts-mocha":"^10.0.0","@types/ms":"^0.7.31","supertest":"^6.3.3","@types/joi":"17.2.3","typescript":"^4.9.4","@types/chai":"^4.3.4","@types/node":"^20.2.5","@types/uuid":"^9.0.0","@types/mocha":"^10.0.1","import-fresh":"^3.3.0","@types/bcrypt":"^5.0.0","@types/config":"^3.3.0","@types/express":"^4.17.15","@types/i18next":"^13.0.0","@types/passport":"1.0.11","i18next-scanner":"^4.1.0","node-mocks-http":"^1.12.1","@types/sequelize":"^4.28.14","@types/supertest":"^2.0.12","@types/deep-extend":"^0.6.0","i18next-fs-backend":"^2.1.1","@types/jsonwebtoken":"^9.0.1","@types/passport-jwt":"^3.0.8","eslint-plugin-import":"^2.27.5","@types/passport-local":"^1.0.35","eslint-plugin-prettier":"^4.2.1","i18next-http-middleware":"^3.2.2","@typescript-eslint/eslint-plugin":"^5.48.2","@goodrequest/eslint-config-typescript":"^1.2.1"},"_npmOperationalInternal":{"tmp":"tmp/passport-jwt-wrapper_1.7.1_1686133617489_0.8882102269667407","host":"s3://npm-registry-packages"}}},"time":{"created":"2023-01-13T11:11:13.783Z","modified":"2026-03-23T11:18:00.647Z","1.1.0-beta":"2023-01-13T11:11:14.089Z","1.1.0":"2023-01-13T13:09:22.056Z","1.1.1":"2023-01-17T11:08:44.666Z","1.2.0":"2023-01-19T11:30:33.744Z","1.2.1":"2023-01-30T14:23:25.964Z","1.2.2":"2023-01-30T15:09:01.115Z","1.2.3":"2023-01-30T15:28:18.305Z","1.2.4":"2023-02-02T11:32:39.309Z","1.3.0":"2023-02-13T18:41:25.147Z","1.3.1-0":"2023-02-14T19:29:24.453Z","1.3.1-1":"2023-02-14T20:55:21.949Z","1.3.1-2":"2023-02-15T11:20:11.567Z","1.3.1":"2023-02-15T11:41:23.477Z","1.4.0-0":"2023-02-23T17:16:37.385Z","1.4.0-1":"2023-02-23T17:53:49.967Z","1.4.0-2":"2023-02-23T19:46:25.828Z","1.4.0-3":"2023-02-23T20:00:05.989Z","1.4.0-6":"2023-02-27T12:41:19.647Z","1.4.0":"2023-03-01T15:28:09.327Z","1.4.1":"2023-03-08T12:03:22.325Z","1.4.2":"2023-03-10T15:27:39.190Z","1.5.0":"2023-04-12T09:00:28.068Z","1.5.1-0":"2023-04-12T13:46:59.804Z","1.5.1-1":"2023-04-13T16:06:19.820Z","1.5.1-2":"2023-04-20T14:15:50.493Z","1.6.0":"2023-04-20T14:24:10.612Z","1.6.1":"2023-04-21T15:01:13.754Z","1.7.0":"2023-05-26T11:13:07.746Z","1.7.1":"2023-06-07T10:26:57.734Z"},"bugs":{"url":"https://github.com/GoodRequest/passport-jwt-wrapper/issues"},"author":{"name":"Juraj Chripko","email":"juraj.chripko@goodrequest.com"},"license":"ISC","homepage":"https://github.com/GoodRequest/passport-jwt-wrapper#readme","keywords":[],"repository":{"url":"git+https://github.com/GoodRequest/passport-jwt-wrapper.git","type":"git"},"description":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml) [![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapp","maintainers":[{"email":"login@goodrequest.com","name":"logingoodrequest"}],"readme":"[![Build and run tests](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/test.yaml)\n[![codecov](https://codecov.io/gh/Slonik923/passport-jwt-wrapper/branch/master/graph/badge.svg?token=5CXS6JGCQF)](https://codecov.io/gh/Slonik923/passport-jwt-wrapper)\n[![Publish package to GitHub Packages](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml/badge.svg)](https://github.com/Slonik923/passport-jwt-wrapper/actions/workflows/publish.yaml)\n\n# JWT Authentication Library\nAuthentication Library developed and used by the GoodRequest s.r.o.\nIt is based on the [express](https://expressjs.com/) framework for Node.js runtime using JWTs.\nIt is wrapper around [passportjs](https://www.passportjs.org/) library designed to minimize boilerplate.\nThis library should take of the user authentication, it is divided into [modules](#modules):\n- Login\n- Securing endpoints\n- Logout\n- Logout from everywhere\n- Refresh token rotation\n- Reset password\n- User invitation\n\n## Installation\n`npm i --save @goodrequest/passport-jwt-wrapper`\n\n## Initialization:\n```typescript\nimport { initAuth } from './index'\nimport * as passport from 'passport'\n\ninitAuth(passport, {\n\t\tuserRepository,\n\t\trefreshTokenRepository,\n\t\tinvitationTokenRepository?,\n\t\tpasswordResetTokenRepository?\n\t}\n)\n```\n\n`invitationTokenRepository` is used for saving and checking validity of invitation tokens.\nThis means, that invitations can be cancelled.\n\n`passwordResetTokenRepository` is similarly used to save and check the validity of password reset tokens.\nThis can be used to cancel password reset.\n\n---\n\n## Usage\n### Login / Logout / Refresh Tokens / Reset Password\n\n```typescript\nimport { Login, RefreshToken, PasswordReset, Logout, LogoutEverywhere, ApiAuth } from '@slonik923/passport-jwt-wrapper'\n\nimport * as postLogin from './post.login'\nimport * as postResetPasswordRequest from './post.resetPasswordRequest'\nimport schemaMiddleware from '../../../middlewares/schemaMiddleware'\n\nconst router = Router()\n\nrouter.post('/login',\n\tschemaMiddleware(postLogin.requestSchema),\n\tLogin.guard,\n\tpostLogin.workflow)\n\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.workflow)\n\nrouter.post('/logout-everywhere',\n\tApiAuth.guard(),\n\tschemaMiddleware(LogoutEverywhere.requestSchema),\n\tLogoutEverywhere.workflow)\n\nrouter.post('/refresh-token',\n\tschemaMiddleware(RefreshToken.requestSchema),\n\tRefreshToken.endpoint)\n\nrouter.post('/reset-password-request',\n\tschemaMiddleware(postResetPasswordRequest.requestSchema()),\n\tpostResetPasswordRequest.workflow)\n\nrouter.post('/reset-password',\n\tschemaMiddleware(PasswordReset.requestSchema),\n\tPasswordReset.guard,\n\tPasswordReset.workflow)\n```\n\n#### Methods that needs to be implemented separately\n\n- `postlogin.workflow` (and `postLogin.requestSchema`): user creation is not in the scope of this library\n- `postResetPasswordRequest.workflow` (and `postResetPasswordRequest.requestSchema`): Reset password email should be\n  sent from this endpoint\n\n### Authentication Guard\n\n[`AuthGuard`](src/apiAuth/guard.ts) is middleware which checks if the request includes valid `access_token` based on jwt\nextractor specified in the config.\nIt needs to be used as function call: `AuthGuard()`, since it uses passport which is provided after this guard is\nimported to your project.\nInternally calls `userRepository.getUserById` to retrieve the user and when `checkAccessToken` is set to\ntrue, `refreshTokenRepository.isRefreshTokenValid` is caleed to find out if the access token is valid.\nAccess token is not only valid, when refresh token issued with given access token was invalidated.\n\n### Configs\n\n[Config interfaces](src/types/config.ts)\n\n`LibConfig`:\n\n```\n{\n\tcheckAccessToken: boolean\n\tpassport: IPassportConfig\n\ti18next: i18next.InitOptions\n}\n```\n\n#### `IPassportConfig`\n\nExample:\n\n```\npassport: {\n\tlocal: {\n\t\tusernameField: 'email',\n\t\tpasswordField: 'password',\n\t\tsession: false,\n\t},\n\tjwt: {\n\t\tsecretOrKey: process.env.JWT_SECRET,\n\t\tapi: {\n\t\t\texp: '15m',\n\t\t\tjwtFromRequest: ExtractJwt.fromExtractors(\n\t\t\t\t[ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('t')]),\n\t\t\trefresh: {\n\t\t\t\texp: '4h',\n\t\t\t}\n\t\t},\n\t\tpasswordReset: {\n\t\t\texp: '4h',\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t},\n\t\tinvitation: {\n\t\t\tjwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n\t\t\texp: '30d',\n\t\t}\n\t}\n},\n```\n\n#### `i18next.InitOptions`\n\nExample:\n\n```\n{\n\tpreload: ['en', 'sk'],\n\tfallbackLng: 'en',\n\tns: ['error', 'translation'],\n\tdefaultNS: 'translation',\n\tdetection: {\n\t\torder: ['header']\n\t},\n\tbackend: {\n\t\tloadPath: 'locales/{{lng}}/{{ns}}.json',\n\tjsonIndent: 2\n\t},\n\tnsSeparator: ':',\n\tkeySeparator: false,\n\treturnNull: false\n}\n```\n\n#### ENV variables\n\nLibrary read from config using [config package](https://www.npmjs.com/package/config).\nConfig needs to have properties specified in [IPassportConfig interface](./src/types/config.ts).\n\n| ENV variable | Development | Production | Note\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t                  |\n|--------------|-------------|------------|--------------------------------------------|\n| JWT_SECRET   | required    | required   | development/test/production\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t |\n\n## Changelog\n### v1.7.0\n - Renamed `workflow` -> `runer` and `endpoint` -> `workflow`. See [issue 69](https://github.com/GoodRequest/passport-jwt-wrapper/issues/69)\n - Locked `joi` package version to v17.7.0\n - Added option to include user hash in `getUserByEmail` and `getUserById` method. See [issue 58](https://github.com/GoodRequest/passport-jwt-wrapper/issues/58)\n\n## Modules\nThis library is divided into modules:\n#### Login\nUsed for logging in users - exchanging user credential for access and refresh tokens.\nExports can be found [here](src/login/index.ts).\n#### RefreshToken\nRefresh tokens have longer validity tha access tokens and can be exchanged for new access and refresh token.\nRefresh tokens are used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).\nExports can be found [here](src/refreshToken/index.ts).\n#### ApiAuth\nModule for securing endpoint. Guard is used to verify that request contains valid access token.\nExports can be found [here](src/apiAuth/index.ts).\n#### Logout\nEndpoint for logging users out. This invalidates whole token family - one user session.\nExports can be found [here](src/logout/index.ts).\n#### LogoutEverywhere\nEndpoint for logging user out from every device (every session).\nExports can be found [here](src/logoutEverywhere/index.ts).\n#### Invitation\nModule used for managing invitation tokens.\nUser invitation is typically done by sending emails, which is not part of this library, so the endpoint needs to be implemented separately.\nExports can be found [here](src/invitation/index.ts).\n#### PasswordReset\nModule for resetting user passwords. Similarly to invitation, this is done by sending emails, so the endpoint needs to be implemented separately.\nExports can be found [here](src/passwordReset/index.ts).\n\n## How does it work (Security perspective)\nEach token types has different payload, expiration and [audience](src/utils/enums.ts).\n#### Token types\n- Access Token:\n\t- Short expiration time (15m)\n    - Stateless - not stored on the server\n    - Cannot be invalidated\n    - No need to access storage for every secure call to the API\n    - payload: `{uid, rid, fid} // userID, refreshTokenID, familyID`\n- Refresh Token\n\t- Longer expiration time (hours)\n    - Stored on the server\n    - Can be invalidated\n    - Used just once ([refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation))\n\t- payload: `{uid, fid, jti} // userID, familyID, JWTID`\n- Invitation Token\n\t- Longer expiration time (hours)\n    - Can be stored on the server (if the `invitationTokenRepository` is provided to the `init` function)\n    - If stored can be invalidated\n    - payload: `{ uid } // userID`\n- Password Reset Token\n\t- Longer expiration time (hours)\n\t- Can be stored on the server (if the `passwordResetTokenRepository` is provided to the `init` function)\n\t- If stored can be invalidated\n\t- payload: `{ uid } // userID`\n\n#### Token family\nAccess and refresh tokens includes `familyID`.\nThis is used to identify login flow.\nNew `familyID` is given every time, user logs in (enter credentials), which means it identifies user session (from login to logout / expiration).\nThis ID is also passed to every subsequent refresh token.\n\nIt is needed for implementing refresh token rotation, but it is also useful for differentiating sessions.\nWhen user (attacker) tries to use the same refresh token (RT1) second time, each refresh token issued based on RT1 needs to be invalidated.\nThis means every refresh token from the same token family.\n\n## Philosophy\nThis library should be used in all GR products, so it needs to be highly **customizable**.\nCustomization is achieved by a combination of technics.\n\n#### Repositories\nLibrary needs access to users and user tokens, but the these are stored different for every project, so to archive compatibility repository pattern is used.\nWhen the library is initialized it needs repositories for creating / getting / invalidating user tokens (JWTs) and for getting users.\n\n#### Helper functions\nAnother way to achieve for greater adaptability is to export helper functions which are used internally on each level.\nThese helper functions can be used to create custom middlewares or endpoints.\n\n#### Architecture\nEach of the modules exports its parts:\n- `getToken[s]`: Helper function for getting tokens (access, refresh, invitation, password reset).\n- `guard`: [Passport.js](https://www.passportjs.org/) authenticate function. Used as middleware to secure endpoints.\n- `strategy`: [Passport.js](https://www.passportjs.org/) strategy.\n- `strategyVerifyFunction`: Helper function used in the strategy.\n- `workflow`: Main function for every endpoint. Can be used to write custom endpoint / middleware.\n- `endpoint`: Whole express endpoint.\n- `requestSchema`: [Joi](https://joi.dev/) request schema. Should be for schema validation for given endpoint.\n- `resposneSchema`: [Joi](https://joi.dev/) response schema. Can be used for documentation.\n\n## API\n### Workflows - Endpoints\nExpress endpoints (`(req, res, next)`). They return object, typically JWTs.\nNeed to be named `workflow`, so swagger documentation is properly generated.\n- [`Logout.endpoint`](./src/logout/workflow.ts): Returns just the message. Internally invalidates refresh token family.\n- [`LogoutEverywhere.endpoint`](src/logoutEverywhere/workflow.ts): Returns just the message. Internally invalidates all users refresh tokens.\n- [`PasswordReset.endpoint`](src/passwordReset/workflow.ts): Returns just the message. Changes user password and invalidates all user refresh tokens, if `userRepository.invalidateUserRefreshTokens` method is provided.\n- [`RefreshToken.endpoint`](src/refreshToken/workflow.ts): Returns new access and refresh tokens. Used refresh token is invalidated, since this library is using refresh token rotation.\n\n### Runner\nInternal function used by endpoint.\n- [`Logout.workflow`](./src/logout/runner.ts)\n- [`LogoutEverywhere.workflow`](src/logoutEverywhere/runner.ts)\n- [`PasswordReset.workflow`](src/passwordReset/runner.ts)\n- [`RefreshToken.workflow`](src/refreshToken/runner.ts)\n\n### Guards\n[express](https://expressjs.com/) middlewares (calls `next` function):\n\n- [`Login.guard`](src/login/guard.ts): helper function calling `passport.authenticate`. Should be used before used\n  specified login endpoint\n- [`ResetPassword.guard`](src/passwordReset/guard.ts): just a helper middleware for the password reset\n- [`ApiAuth.guard`](src/apiAuth/guard.ts): see [Authentication Guard](#Authentication-Guard)\n\n### Functions\nFunction used in project specific middlewares, or endpoints.\n- [`Login.getTokens(userID: string | number, familyID?: string | number)`](src/login/getTokens.ts): Used in the login endpoint and in refresh token endpoint.\n- [`PasswordReset.getToken(email: string)`](src/passwordReset/getToken.ts): Used in the reset password endpoint. Token created by this function should be sent to the user (probably by email).\nThis function is accessible without authorization, so it should not leak any information about users, that's why the execution should take approximately same time for valid and invalid input. More in the [constant time chapter](#constant-time-methods)\n- [`Invitation.getToken(userID: string | number)`](src/invitation/getToken.ts): Should be user in the user invitation endpoint. Returns token with given userID.\n\n### Schemas\nEvery module which exports endpoint also exports [Joi](https://joi.dev/)  `requestSchema` and `responseSchema`\nrouter.post('/logout',\n\tApiAuth.guard(),\n\tschemaMiddleware(Logout.requestSchema),\n\tLogout.endpoint)\n### Other\nThis library also exports helper functions, enums and types. All exports can be found in the [index.ts](src/index.ts).\n\n#### Constant time methods\nSome methods can leak information about user based on the execution time. One of these methods is `PasswordReset.getToken`.\nIt is accessible without authorization, so the attacker could find out emails of the registered users, which could be a problem for some applications.\nThat why execution of this method should be more, less constant.\nExecution times before triage:\n```text\naverage execution time: 0.0087ms\naverage invalid execution time: 0.0008ms\naverage valid execution time: 0.0166ms\n```\nThere is huge difference in execution time based on valid input vs. invalid input.\n\nExecution times before triage:\n```text\naverage execution time: 0.0136ms\naverage invalid execution time: 0.0141ms\naverage valid execution time: 0.0131ms\n```\nExecution now takes more time, when the input is invalid, but that can change when passwordResetToken repository is used, since only valid tokens will be saved.\nMeasurements heavily depend on the compilation and code optimization done by compiler, so in production this could vary.\nThese numbers are average from 1000 iterations, after 10 000 iterations warm-up, so JIT compiler can do it's job.\nMore on these tests can in the [`getToken.test.ts`](./tests/cases/passwordReset/getToken.test.ts).\n","readmeFilename":"README.md"}