[
  {
    "path": ".commitlintrc.json",
    "content": "{\n  \"extends\": [\"@commitlint/config-conventional\"]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".eslintignore",
    "content": ".nyc_output/\ncoverage/\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"parserOptions\": {\n    \"ecmaVersion\": 6\n  },\n  \"env\": {\n    \"es6\": true,\n    \"node\": true\n  },\n  \"rules\": {\n    \"comma-style\": \"error\",\n    \"dot-notation\": \"error\",\n    \"indent\": [\"error\", 2],\n    \"no-control-regex\": \"error\",\n    \"no-div-regex\": \"error\",\n    \"no-eval\": \"error\",\n    \"no-implied-eval\": \"error\",\n    \"no-invalid-regexp\": \"error\",\n    \"no-trailing-spaces\": \"error\",\n    \"no-undef\": \"error\",\n    \"no-unused-vars\": \"error\"\n  }\n}\n"
  },
  {
    "path": ".github/workflows/commitlint.yml",
    "content": "name: Lint Commits\n\non:\n  pull_request:\n\njobs:\n  commitlint:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Setup Node.js\n        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0\n        with:\n          node-version: '24'\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Validate commit messages\n        run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose\n"
  },
  {
    "path": ".github/workflows/prepare-release.yml",
    "content": "name: Prepare Release\n\non:\n  push:\n    branches:\n      - master\n\nconcurrency:\n  group: prepare-release\n  cancel-in-progress: true\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  prepare:\n    runs-on: ubuntu-latest\n    if: \"!startsWith(github.event.head_commit.message, 'chore(release):')\"\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Setup Node.js\n        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0\n        with:\n          node-version: '24'\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Detect Next Version\n        id: version\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          NEXT_VERSION=$(npx semantic-release --dry-run --plugins @semantic-release/commit-analyzer | tee /dev/stderr | awk '/The next release version is/{print $NF}')\n          echo \"next=$NEXT_VERSION\" >> $GITHUB_OUTPUT\n\n      - name: Update package.json\n        if: steps.version.outputs.next != ''\n        run: npm version \"$NEXT_VERSION\" --no-git-tag-version\n        env:\n          NEXT_VERSION: ${{ steps.version.outputs.next }}\n\n      - name: Update CHANGELOG.md\n        if: steps.version.outputs.next != ''\n        run: npx conventional-changelog-cli -p angular -i CHANGELOG.md -s\n\n      - name: Create Pull Request\n        if: steps.version.outputs.next != ''\n        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          commit-message: \"chore(release): ${{ steps.version.outputs.next }}\"\n          branch: \"release/v${{ steps.version.outputs.next }}\"\n          delete-branch: true\n          title: \"chore(release): ${{ steps.version.outputs.next }}\"\n          body: |\n            This PR prepares the release of version ${{ steps.version.outputs.next }}.\n\n            **Changes:**\n            - Updated version in `package.json` to ${{ steps.version.outputs.next }}\n            - Updated `CHANGELOG.md` with release notes\n\n            **Next Steps:**\n            Review and merge this PR to trigger the publish workflow.\n          labels: release\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\npermissions:\n  contents: write\n  issues: write\n  pull-requests: write\n  id-token: write\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    if: startsWith(github.event.head_commit.message, 'chore(release):')\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n\n      - name: Setup Node.js\n        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0\n        with:\n          node-version: '24'\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version: \"3.10\"\n\n      - name: Install Python dependencies\n        shell: bash\n        run: pip install boto3>=1.34.159 requests>=2.32.3 rl-deploy>=2.2.3.0 pip-system-certs>=4.0\n\n      - name: Configure AWS credentials\n        uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0\n        with:\n          role-to-assume: ${{ secrets.PRODSEC_TOOLS_ARN }}\n          aws-region: us-east-1\n          mask-aws-account-id: true\n\n      - name: Install rl-wrapper\n        env:\n          WRAPPER_INDEX_URL: \"https://${{ secrets.PRODSEC_TOOLS_USER }}:${{ secrets.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple\"\n        run: pip install \"rl-wrapper>=1.0.0\" --index-url $WRAPPER_INDEX_URL\n\n      - name: Release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_CONFIG_PROVENANCE: true\n          RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }}\n          RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }}\n          SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }}\n          PYTHONUNBUFFERED: 1\n        run: npx semantic-release\n"
  },
  {
    "path": ".github/workflows/sca-scan.yml",
    "content": "name: Snyk Scan\n\non:\n  push:\n    branches: [\"master\"]\n\njobs:\n  snyk-cli:\n    uses: auth0/devsecops-tooling/.github/workflows/sca-scan.yml@5246a8b59100e3eea284ce4f2e2a51b51e237380\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    strategy:\n      fail-fast: false\n      matrix:\n        node: [16, 18, 20, 22, 24]\n\n    name: Test (Node ${{ matrix.node }})\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Setup Node\n        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0\n        with:\n          node-version: ${{ matrix.node }}\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Test\n        run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\n.nyc_output\ncoverage\npackage-lock.json\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "npx --no -- commitlint --edit ${1}\n"
  },
  {
    "path": ".npmignore",
    "content": "opslevel.yml"
  },
  {
    "path": ".releaserc.json",
    "content": "{\n  \"branches\": [\n    \"master\"\n  ],\n  \"plugins\": [\n    \"@semantic-release/commit-analyzer\",\n    \"@semantic-release/release-notes-generator\",\n    [\n      \"@semantic-release/npm\",\n      {\n        \"npmPublish\": true,\n        \"pkgRoot\": \".\"\n      }\n    ],\n    [\n      \"@semantic-release/exec\",\n      {\n        \"verifyReleaseCmd\": \"ARTIFACT=\\\"$(pwd)/$(npm pack --ignore-scripts | tail -1)\\\" && rl-wrapper --artifact \\\"$ARTIFACT\\\" --name jsonwebtoken --version ${nextRelease.version} --repository $GITHUB_REPOSITORY --commit $GITHUB_SHA --build-env github_actions --suppress-output\",\n        \"prepareCmd\": \"git diff --exit-code\"\n      }\n    ],\n    \"@semantic-release/github\"\n  ]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\n\nAll notable changes to this project will be documented in this file starting from version **v4.0.0**.\nThis project adheres to [Semantic Versioning](http://semver.org/).\n\n## 9.0.3 - 2025-12-04\n\n- updates jws version to 4.0.1.\n\n## 9.0.2 - 2023-08-30\n\n- security: updating semver to 7.5.4 to resolve CVE-2022-25883, closes [#921](https://github.com/auth0/node-jsonwebtoken/issues/921).\n- refactor: reduce library size by using lodash specific dependencies, closes [#878](https://github.com/auth0/node-jsonwebtoken/issues/878).\n\n## 9.0.1 - 2023-07-05\n\n- fix(stubs): allow decode method to be stubbed\n\n## 9.0.0 - 2022-12-21\n\n  **Breaking changes: See [Migration from v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)**\n\n### Breaking changes\n\n- Removed support for Node versions 11 and below.\n- The verify() function no longer accepts unsigned tokens by default. ([834503079514b72264fd13023a3b8d648afd6a16]https://github.com/auth0/node-jsonwebtoken/commit/834503079514b72264fd13023a3b8d648afd6a16)\n- RSA key size must be 2048 bits or greater. ([ecdf6cc6073ea13a7e71df5fad043550f08d0fa6]https://github.com/auth0/node-jsonwebtoken/commit/ecdf6cc6073ea13a7e71df5fad043550f08d0fa6)\n- Key types must be valid for the signing / verification algorithm\n\n### Security fixes\n\n- security: fixes `Arbitrary File Write via verify function` - CVE-2022-23529\n- security: fixes `Insecure default algorithm in jwt.verify() could lead to signature validation bypass` - CVE-2022-23540\n- security: fixes `Insecure implementation of key retrieval function could lead to Forgeable Public/Private Tokens from RSA to HMAC` - CVE-2022-23541\n- security: fixes `Unrestricted key type could lead to legacy keys usage` - CVE-2022-23539\n\n## 8.5.1 - 2019-03-18\n\n### Bug fix\n\n - fix: ensure correct PS signing and verification (#585) ([e5874ae428ffc0465e6bd4e660f89f78b56a74a6](https://github.com/auth0/node-jsonwebtoken/commit/e5874ae428ffc0465e6bd4e660f89f78b56a74a6)), closes [#585](https://github.com/auth0/node-jsonwebtoken/issues/585)\n\n### Docs\n\n - README: fix markdown for algorithms table ([84e03ef70f9c44a3aef95a1dc122c8238854f683](https://github.com/auth0/node-jsonwebtoken/commit/84e03ef70f9c44a3aef95a1dc122c8238854f683))\n\n## 8.5.0 - 2019-02-20\n\n### New Functionality\n\n - feat: add PS JWA support for applicable node versions (#573) ([eefb9d9c6eec54718fa6e41306bda84788df7bec](https://github.com/auth0/node-jsonwebtoken/commit/eefb9d9c6eec54718fa6e41306bda84788df7bec)), closes [#573](https://github.com/auth0/node-jsonwebtoken/issues/573)\n - Add complete option in jwt.verify (#522) ([8737789dd330cf9e7870f4df97fd52479adbac22](https://github.com/auth0/node-jsonwebtoken/commit/8737789dd330cf9e7870f4df97fd52479adbac22)), closes [#522](https://github.com/auth0/node-jsonwebtoken/issues/522)\n\n ### Test Improvements\n\n - Add tests for private claims in the payload (#555) ([5147852896755dc1291825e2e40556f964411fb2](https://github.com/auth0/node-jsonwebtoken/commit/5147852896755dc1291825e2e40556f964411fb2)), closes [#555](https://github.com/auth0/node-jsonwebtoken/issues/555)\n - Force use_strict during testing (#577) ([7b60c127ceade36c33ff33be066e435802001c94](https://github.com/auth0/node-jsonwebtoken/commit/7b60c127ceade36c33ff33be066e435802001c94)), closes [#577](https://github.com/auth0/node-jsonwebtoken/issues/577)\n - Refactor tests related to jti and jwtid (#544) ([7eebbc75ab89e01af5dacf2aae90fe05a13a1454](https://github.com/auth0/node-jsonwebtoken/commit/7eebbc75ab89e01af5dacf2aae90fe05a13a1454)), closes [#544](https://github.com/auth0/node-jsonwebtoken/issues/544)\n - ci: remove nsp from tests (#569) ([da8f55c3c7b4dd0bfc07a2df228500fdd050242a](https://github.com/auth0/node-jsonwebtoken/commit/da8f55c3c7b4dd0bfc07a2df228500fdd050242a)), closes [#569](https://github.com/auth0/node-jsonwebtoken/issues/569)\n\n### Docs\n\n- Fix 'cert' token which isn't a cert (#554) ([0c24fe68cd2866cea6322016bf993cd897fefc98](https://github.com/auth0/node-jsonwebtoken/commit/0c24fe68cd2866cea6322016bf993cd897fefc98)), closes [#554](https://github.com/auth0/node-jsonwebtoken/issues/554)\n\n\n## 8.4.0 - 2018-11-14\n\n### New Functionality\n\n - Add verify option for nonce validation (#540) ([e7938f06fdf2ed3aa88745b72b8ae4ee66c2d0d0](https://github.com/auth0/node-jsonwebtoken/commit/e7938f06fdf2ed3aa88745b72b8ae4ee66c2d0d0)), closes [#540](https://github.com/auth0/node-jsonwebtoken/issues/540)\n\n### Bug Fixes\n\n - Updating Node version in Engines spec in package.json (#528) ([cfd1079305170a897dee6a5f55039783e6ee2711](https://github.com/auth0/node-jsonwebtoken/commit/cfd1079305170a897dee6a5f55039783e6ee2711)), closes [#528](https://github.com/auth0/node-jsonwebtoken/issues/528) [#509](https://github.com/auth0/node-jsonwebtoken/issues/509)\n - Fixed error message when empty string passed as expiresIn or notBefore option (#531) ([7f9604ac98d4d0ff8d873c3d2b2ea64bd285cb76](https://github.com/auth0/node-jsonwebtoken/commit/7f9604ac98d4d0ff8d873c3d2b2ea64bd285cb76)), closes [#531](https://github.com/auth0/node-jsonwebtoken/issues/531)\n\n### Docs\n\n - Update README.md (#527) ([b76f2a80f5229ee5cde321dd2ff14aa5df16d283](https://github.com/auth0/node-jsonwebtoken/commit/b76f2a80f5229ee5cde321dd2ff14aa5df16d283)), closes [#527](https://github.com/auth0/node-jsonwebtoken/issues/527)\n - Update README.md (#538) ([1956c4006472fd285b8a85074257cbdbe9131cbf](https://github.com/auth0/node-jsonwebtoken/commit/1956c4006472fd285b8a85074257cbdbe9131cbf)), closes [#538](https://github.com/auth0/node-jsonwebtoken/issues/538)\n - Edited the README.md to make certain parts of the document for the api easier to read, emphasizing the examples. (#548) ([dc89a641293d42f72ecfc623ce2eabc33954cb9d](https://github.com/auth0/node-jsonwebtoken/commit/dc89a641293d42f72ecfc623ce2eabc33954cb9d)), closes [#548](https://github.com/auth0/node-jsonwebtoken/issues/548)\n - Document NotBeforeError (#529) ([29cd654b956529e939ae8f8c30b9da7063aad501](https://github.com/auth0/node-jsonwebtoken/commit/29cd654b956529e939ae8f8c30b9da7063aad501)), closes [#529](https://github.com/auth0/node-jsonwebtoken/issues/529)\n\n### Test Improvements\n\n - Use lolex for faking date in tests (#491) ([677ead6d64482f2067b11437dda07309abe73cfa](https://github.com/auth0/node-jsonwebtoken/commit/677ead6d64482f2067b11437dda07309abe73cfa)), closes [#491](https://github.com/auth0/node-jsonwebtoken/issues/491)\n - Update dependencies used for running tests (#518) ([5498bdc4865ffb2ba2fd44d889fad7e83873bb33](https://github.com/auth0/node-jsonwebtoken/commit/5498bdc4865ffb2ba2fd44d889fad7e83873bb33)), closes [#518](https://github.com/auth0/node-jsonwebtoken/issues/518)\n - Minor test refactoring for recently added tests (#504) ([e2860a9d2a412627d79741a95bc7159971b923b9](https://github.com/auth0/node-jsonwebtoken/commit/e2860a9d2a412627d79741a95bc7159971b923b9)), closes [#504](https://github.com/auth0/node-jsonwebtoken/issues/504)\n - Create and implement async/sync test helpers (#523) ([683d8a9b31ad6327948f84268bd2c8e4350779d1](https://github.com/auth0/node-jsonwebtoken/commit/683d8a9b31ad6327948f84268bd2c8e4350779d1)), closes [#523](https://github.com/auth0/node-jsonwebtoken/issues/523)\n - Refactor tests related to audience and aud (#503) ([53d405e0223cce7c83cb51ecf290ca6bec1e9679](https://github.com/auth0/node-jsonwebtoken/commit/53d405e0223cce7c83cb51ecf290ca6bec1e9679)), closes [#503](https://github.com/auth0/node-jsonwebtoken/issues/503)\n - Refactor tests related to expiresIn and exp (#501) ([72f0d9e5b11a99082250665d1200c58182903fa6](https://github.com/auth0/node-jsonwebtoken/commit/72f0d9e5b11a99082250665d1200c58182903fa6)), closes [#501](https://github.com/auth0/node-jsonwebtoken/issues/501)\n - Refactor tests related to iat and maxAge (#507) ([877bd57ab2aca9b7d230805b21f921baed3da169](https://github.com/auth0/node-jsonwebtoken/commit/877bd57ab2aca9b7d230805b21f921baed3da169)), closes [#507](https://github.com/auth0/node-jsonwebtoken/issues/507)\n - Refactor tests related to iss and issuer (#543) ([0906a3fa80f52f959ac1b6343d3024ce5c7e9dea](https://github.com/auth0/node-jsonwebtoken/commit/0906a3fa80f52f959ac1b6343d3024ce5c7e9dea)), closes [#543](https://github.com/auth0/node-jsonwebtoken/issues/543)\n - Refactor tests related to kid and keyid (#545) ([88645427a0adb420bd3e149199a2a6bf1e17277e](https://github.com/auth0/node-jsonwebtoken/commit/88645427a0adb420bd3e149199a2a6bf1e17277e)), closes [#545](https://github.com/auth0/node-jsonwebtoken/issues/545)\n - Refactor tests related to notBefore and nbf (#497) ([39adf87a6faef3df984140f88e6724ddd709fd89](https://github.com/auth0/node-jsonwebtoken/commit/39adf87a6faef3df984140f88e6724ddd709fd89)), closes [#497](https://github.com/auth0/node-jsonwebtoken/issues/497)\n - Refactor tests related to subject and sub (#505) ([5a7fa23c0b4ac6c25304dab8767ef840b43a0eca](https://github.com/auth0/node-jsonwebtoken/commit/5a7fa23c0b4ac6c25304dab8767ef840b43a0eca)), closes [#505](https://github.com/auth0/node-jsonwebtoken/issues/505)\n - Implement async/sync tests for exp claim (#536) ([9ae3f207ac64b7450ea0a3434418f5ca58d8125e](https://github.com/auth0/node-jsonwebtoken/commit/9ae3f207ac64b7450ea0a3434418f5ca58d8125e)), closes [#536](https://github.com/auth0/node-jsonwebtoken/issues/536)\n - Implement async/sync tests for nbf claim (#537) ([88bc965061ed65299a395f42a100fb8f8c3c683e](https://github.com/auth0/node-jsonwebtoken/commit/88bc965061ed65299a395f42a100fb8f8c3c683e)), closes [#537](https://github.com/auth0/node-jsonwebtoken/issues/537)\n - Implement async/sync tests for sub claim (#534) ([342b07bb105a35739eb91265ba5b9dd33c300fc6](https://github.com/auth0/node-jsonwebtoken/commit/342b07bb105a35739eb91265ba5b9dd33c300fc6)), closes [#534](https://github.com/auth0/node-jsonwebtoken/issues/534)\n - Implement async/sync tests for the aud claim (#535) ([1c8ff5a68e6da73af2809c9d87faaf78602c99bb](https://github.com/auth0/node-jsonwebtoken/commit/1c8ff5a68e6da73af2809c9d87faaf78602c99bb)), closes [#535](https://github.com/auth0/node-jsonwebtoken/issues/535)\n\n### CI\n\n - Added Istanbul to check test-coverage (#468) ([9676a8306428a045e34c3987bd0680fb952b44e3](https://github.com/auth0/node-jsonwebtoken/commit/9676a8306428a045e34c3987bd0680fb952b44e3)), closes [#468](https://github.com/auth0/node-jsonwebtoken/issues/468)\n - Complete ESLint conversion and cleanup (#490) ([cb1d2e1e40547f7ecf29fa6635041df6cbba7f40](https://github.com/auth0/node-jsonwebtoken/commit/cb1d2e1e40547f7ecf29fa6635041df6cbba7f40)), closes [#490](https://github.com/auth0/node-jsonwebtoken/issues/490)\n - Make code-coverage mandatory when running tests (#495) ([fb0084a78535bfea8d0087c0870e7e3614a2cbe5](https://github.com/auth0/node-jsonwebtoken/commit/fb0084a78535bfea8d0087c0870e7e3614a2cbe5)), closes [#495](https://github.com/auth0/node-jsonwebtoken/issues/495)\n\n\n## 8.3.0 - 2018-06-11\n\n - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473)\n - ci: fix ci execution, remove not needed script (#472) ([c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5](https://github.com/auth0/node-jsonwebtoken/commit/c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5)), closes [#472](https://github.com/auth0/node-jsonwebtoken/issues/472)\n - new feature: Secret callback revisited (#480) ([d01cc7bcbdeb606d997a580f967b3169fcc622ba](https://github.com/auth0/node-jsonwebtoken/commit/d01cc7bcbdeb606d997a580f967b3169fcc622ba)), closes [#480](https://github.com/auth0/node-jsonwebtoken/issues/480)\n - docs:Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461)\n\n\n## 8.2.2 - 2018-05-30\n\n - security: deps: jws@3.1.5 (#477) ([ebde9b7cc75cb7ab5176de7ebc4a1d6a8f05bd51](https://github.com/auth0/node-jsonwebtoken/commit/ebde9b7cc75cb7ab5176de7ebc4a1d6a8f05bd51)), closes [#465](https://github.com/auth0/node-jsonwebtoken/issues/465)\n - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473)\n - ci: fix ci execution, remove not needed script (#472) ([c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5](https://github.com/auth0/node-jsonwebtoken/commit/c8ff7b2c3ffcd954a64a0273c20a7d1b22339aa5)), closes [#472](https://github.com/auth0/node-jsonwebtoken/issues/472)\n - docs: Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461)\n\n\n## 8.2.1 - 2018-04-05\n\n - bug fix: Check payload is not null when decoded. (#444) ([1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5](https://github.com/auth0/node-jsonwebtoken/commit/1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5))\n - docs: Clarify that buffer/string payloads must be JSON (#442) ([e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b](https://github.com/auth0/node-jsonwebtoken/commit/e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b))\n\n\n## 8.2.0 - 2018-03-02\n\n - Add a new mutatePayload option (#446) ([d6d7c5e5103f05a92d3633ac190d3025a0455be0](https://github.com/auth0/node-jsonwebtoken/commit/d6d7c5e5103f05a92d3633ac190d3025a0455be0))\n\n\n## 8.1.1 - 2018-01-22\n\n - ci: add newer node versions to build matrix (#428) ([83f3eee44e122da06f812d7da4ace1fa26c24d9d](https://github.com/auth0/node-jsonwebtoken/commit/83f3eee44e122da06f812d7da4ace1fa26c24d9d))\n - deps: Bump ms version to add support for negative numbers (#438) ([25e0e624545eaef76f3c324a134bf103bc394724](https://github.com/auth0/node-jsonwebtoken/commit/25e0e624545eaef76f3c324a134bf103bc394724))\n - docs: Minor typo (#424) ([dddcb73ac05de11b81feeb629f6cf78dd03d2047](https://github.com/auth0/node-jsonwebtoken/commit/dddcb73ac05de11b81feeb629f6cf78dd03d2047))\n - bug fix: Not Before (nbf) calculated based on iat/timestamp (#437) ([2764a64908d97c043d62eba0bf6c600674f9a6d6](https://github.com/auth0/node-jsonwebtoken/commit/2764a64908d97c043d62eba0bf6c600674f9a6d6)), closes [#435](https://github.com/auth0/node-jsonwebtoken/issues/435)\n\n\n## 8.1.0 - 2017-10-09\n\n - #402: Don't fail if captureStackTrace is not a function (#410) ([77ee965d9081faaf21650f266399f203f69533c5](https://github.com/auth0/node-jsonwebtoken/commit/77ee965d9081faaf21650f266399f203f69533c5))\n - #403: Clarify error wording for \"Expected object\" error. (#409) ([bb27eb346f0ff675a320b2de16b391a7cfeadc58](https://github.com/auth0/node-jsonwebtoken/commit/bb27eb346f0ff675a320b2de16b391a7cfeadc58))\n - Enhance audience check to verify against regular expressions (#398) ([81501a17da230af7b74a3f7535ab5cd3a19c8315](https://github.com/auth0/node-jsonwebtoken/commit/81501a17da230af7b74a3f7535ab5cd3a19c8315))\n\n\n## 8.0.1 - 2017-09-12\n\n - Remove `lodash.isarray` dependency (#394) ([7508e8957cb1c778f72fa9a363a7b135b3c9c36d](https://github.com/auth0/node-jsonwebtoken/commit/7508e8957cb1c778f72fa9a363a7b135b3c9c36d))\n\n## 8.0.0 - 2017-09-06\n\n  **Breaking changes: See [Migration notes from v7](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)**\n\n - docs: readme, migration notes ([12cd8f7f47224f904f6b8f39d1dee73775de4f6f](https://github.com/auth0/node-jsonwebtoken/commit/12cd8f7f47224f904f6b8f39d1dee73775de4f6f))\n - verify: remove process.nextTick (#302) ([3305cf04e3f674b9fb7e27c9b14ddd159650ff82](https://github.com/auth0/node-jsonwebtoken/commit/3305cf04e3f674b9fb7e27c9b14ddd159650ff82))\n - Reduce size of NPM package (#347) ([0be5409ac6592eeaae373dce91ec992fa101bd8a](https://github.com/auth0/node-jsonwebtoken/commit/0be5409ac6592eeaae373dce91ec992fa101bd8a))\n - Remove joi to shrink module size (#348) ([2e7e68dbd59e845cdd940afae0a296f48438445f](https://github.com/auth0/node-jsonwebtoken/commit/2e7e68dbd59e845cdd940afae0a296f48438445f))\n - maxAge: Add validation to timespan result ([66a4f8b996c8357727ce62a84605a005b2f5eb18](https://github.com/auth0/node-jsonwebtoken/commit/66a4f8b996c8357727ce62a84605a005b2f5eb18))\n\n## 7.4.3 - 2017-08-17\n\n - Fix breaking change on 7.4.2 for empty secret + \"none\" algorithm (sync code style) ([PR 386](https://github.com/auth0/node-jsonwebtoken/pull/386))\n\n## 7.4.2 - 2017-08-04\n\n - bugfix: sign: add check to be sure secret has a value ([c584d1cbc34b788977b36f17cd57ab2212f1230e](https://github.com/auth0/node-jsonwebtoken/commit/c584d1cbc34b788977b36f17cd57ab2212f1230e))\n - docs: about refreshing tokens ([016fc10b847bfbb76b82171cb530f32d7da2001b](https://github.com/auth0/node-jsonwebtoken/commit/016fc10b847bfbb76b82171cb530f32d7da2001b))\n - docs: verifying with base64 encoded secrets ([c25e9906801f89605080cc71b3ee23a5e45a5811](https://github.com/auth0/node-jsonwebtoken/commit/c25e9906801f89605080cc71b3ee23a5e45a5811))\n - tests: Add tests for ES256 ([89900ea00735f76b04f437c9f542285b420fa9cb](https://github.com/auth0/node-jsonwebtoken/commit/89900ea00735f76b04f437c9f542285b420fa9cb))\n - docs: document keyid as option (#361) ([00086c2c006d7fc1a47bae02fa87d194d79aa558](https://github.com/auth0/node-jsonwebtoken/commit/00086c2c006d7fc1a47bae02fa87d194d79aa558))\n - docs: readme: Using private key with passpharase (#353) ([27a7f1d4f35b662426ff0270526d48658da4c8b7](https://github.com/auth0/node-jsonwebtoken/commit/27a7f1d4f35b662426ff0270526d48658da4c8b7))\n\n## 7.4.1 - 2017-05-17\n\n - bump ms to v2 due a ReDoS vulnerability (#352) ([adcfd6ae4088c838769d169f8cd9154265aa13e0](https://github.com/auth0/node-jsonwebtoken/commit/adcfd6ae4088c838769d169f8cd9154265aa13e0))\n\n## 7.4.0 - 2017-04-24\n\n - Add docs about numeric date fields ([659f73119900a4d837650d9b3f5af4e64a2f843b](https://github.com/auth0/node-jsonwebtoken/commit/659f73119900a4d837650d9b3f5af4e64a2f843b))\n - Make Options object optional for callback-ish sign ([e202c4fd00c35a24e9ab606eab89186ade13d0cc](https://github.com/auth0/node-jsonwebtoken/commit/e202c4fd00c35a24e9ab606eab89186ade13d0cc))\n\n## 7.3.0 - 2017-02-13\n\n - Add more information to `maxAge` option in README ([1b0592e99cc8def293eed177e2575fa7f1cf7aa5](https://github.com/auth0/node-jsonwebtoken/commit/1b0592e99cc8def293eed177e2575fa7f1cf7aa5))\n - Add `clockTimestamp` option to `verify()` you can set the current time in seconds with it (#274) ([8fdc1504f4325e7003894ffea078da9cba5208d9](https://github.com/auth0/node-jsonwebtoken/commit/8fdc1504f4325e7003894ffea078da9cba5208d9))\n - Fix handling non string tokens on `verify()` input (#305) ([1b6ec8d466504f58c5a6e2dae3360c828bad92fb](https://github.com/auth0/node-jsonwebtoken/commit/1b6ec8d466504f58c5a6e2dae3360c828bad92fb)), closes [#305](https://github.com/auth0/node-jsonwebtoken/issues/305)\n - Fixed a simple typo in docs (#287) ([a54240384e24e18c00e75884295306db311d0cb7](https://github.com/auth0/node-jsonwebtoken/commit/a54240384e24e18c00e75884295306db311d0cb7)), closes [#287](https://github.com/auth0/node-jsonwebtoken/issues/287)\n - Raise jws.decode error to avoid confusion with \"invalid token\" error  (#294) ([7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e](https://github.com/auth0/node-jsonwebtoken/commit/7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e))\n - rauchg/ms.js changed to zeit/ms (#303) ([35d84152a6b716d757cb5b1dd3c79fe3a1bc0628](https://github.com/auth0/node-jsonwebtoken/commit/35d84152a6b716d757cb5b1dd3c79fe3a1bc0628))\n\n## 7.2.1 - 2016-12-07\n\n - add nsp check to find vulnerabilities on npm test ([4219c34b5346811c07f520f10516cc495bcc70dd](https://github.com/auth0/node-jsonwebtoken/commit/4219c34b5346811c07f520f10516cc495bcc70dd))\n - revert to joi@^6 to keep ES5 compatibility ([51d4796c07344bf817687f7ccfeef78f00bf5b4f](https://github.com/auth0/node-jsonwebtoken/commit/51d4796c07344bf817687f7ccfeef78f00bf5b4f))\n\n## 7.2.0 - 2016-12-06\n\n - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0))\n - Restructured a sentence ([ccc7610187a862f7a50177eadc9152eef26cd065](https://github.com/auth0/node-jsonwebtoken/commit/ccc7610187a862f7a50177eadc9152eef26cd065))\n - Allow `keyid` on `sign`. ([b412be91b89acb3a742bb609d3b54e47e1dfc441](https://github.com/auth0/node-jsonwebtoken/commit/b412be91b89acb3a742bb609d3b54e47e1dfc441))\n - upgrade joi ([715e3d928023d414d45c6dc3f096a7c8448139ae](https://github.com/auth0/node-jsonwebtoken/commit/715e3d928023d414d45c6dc3f096a7c8448139ae))\n - upgrade to latest nodes and Travis infrastructure ([3febcc1dd23ecdec1abbf89313959941d15eb47a](https://github.com/auth0/node-jsonwebtoken/commit/3febcc1dd23ecdec1abbf89313959941d15eb47a))\n\n\n## 7.1.10 - 2016-12-06\n\n - Bump node-jws version number ([07813dd7194630c9f452684279178af76464a759](https://github.com/auth0/node-jsonwebtoken/commit/07813dd7194630c9f452684279178af76464a759))\n - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0))\n\n## 7.1.9 - 2016-08-11\n\n - Revert \"Merge branch 'venatir-master'\" ([d06359ef3b4e619680e043ee7c16adda16598f52](https://github.com/auth0/node-jsonwebtoken/commit/d06359ef3b4e619680e043ee7c16adda16598f52))\n\n\n\n## 7.1.8 - 2016-08-10\n\n - Fixed tests, however typ: 'JWT' should not be in the options at all, so please review other tests ([01903bcdc61b4ed429acbbd1fe0ffe0db364473b](https://github.com/auth0/node-jsonwebtoken/commit/01903bcdc61b4ed429acbbd1fe0ffe0db364473b))\n - Removing unnecessary extra decoding. jwtString is already verified as valid and signature checked ([55d5834f7b637011e1d8b927ff78a92a5fd521cf](https://github.com/auth0/node-jsonwebtoken/commit/55d5834f7b637011e1d8b927ff78a92a5fd521cf))\n - update changelog ([5117aacd0118a10331889a64e61d8186112d8a23](https://github.com/auth0/node-jsonwebtoken/commit/5117aacd0118a10331889a64e61d8186112d8a23))\n\n\n## 7.1.7 - 2016-07-29\n\n - Use lodash.once instead of unlicensed/unmaintained cb ([3ac95ad93ef3068a64e03d8d14deff231b1ed529](https://github.com/auth0/node-jsonwebtoken/commit/3ac95ad93ef3068a64e03d8d14deff231b1ed529))\n\n## 7.1.6 - 2016-07-15\n\n - fix issue with buffer payload. closes #216 ([6b50ff324b4dfd2cb0e49b666f14a6672d015b22](https://github.com/auth0/node-jsonwebtoken/commit/6b50ff324b4dfd2cb0e49b666f14a6672d015b22)), closes [#216](https://github.com/auth0/node-jsonwebtoken/issues/216)\n\n\n## 7.1.5 - 2016-07-15\n\n - update jws in package.json ([b6260951eefc68aae5f4ede359210761f901ff7a](https://github.com/auth0/node-jsonwebtoken/commit/b6260951eefc68aae5f4ede359210761f901ff7a))\n\n\n## 7.1.4 - 2016-07-14\n\n - add redundant test ([bece8816096f324511c3efcb8db0e64b75d757a1](https://github.com/auth0/node-jsonwebtoken/commit/bece8816096f324511c3efcb8db0e64b75d757a1))\n - fix an issue of double callback on error ([758ca5eeca2f1b06c32c9fce70642bf488b2e52b](https://github.com/auth0/node-jsonwebtoken/commit/758ca5eeca2f1b06c32c9fce70642bf488b2e52b))\n\n## 7.1.2 - 2016-07-12\n\n - do not stringify the payload when signing async - closes #224 ([084f537d3dfbcef2bea411cc0a1515899cc8aa21](https://github.com/auth0/node-jsonwebtoken/commit/084f537d3dfbcef2bea411cc0a1515899cc8aa21)), closes [#224](https://github.com/auth0/node-jsonwebtoken/issues/224)\n\n## 7.1.1 - 2016-07-12\n\n - do not mutate options in jwt.verify, closes #227 ([63263a28a268624dab0927b9ad86fffa44a10f84](https://github.com/auth0/node-jsonwebtoken/commit/63263a28a268624dab0927b9ad86fffa44a10f84)), closes [#227](https://github.com/auth0/node-jsonwebtoken/issues/227)\n - refactor into multiple files ([e11d505207fa33501298300c9accbfb809d8748d](https://github.com/auth0/node-jsonwebtoken/commit/e11d505207fa33501298300c9accbfb809d8748d))\n\n## 7.1.0 - 2016-07-12\n\n - Exp calculated based on iat. fix #217 ([757a16e0e35ad19f9e456820f55d5d9f3fc76aee](https://github.com/auth0/node-jsonwebtoken/commit/757a16e0e35ad19f9e456820f55d5d9f3fc76aee)), closes [#217](https://github.com/auth0/node-jsonwebtoken/issues/217)\n\n## 7.0.0 - 2016-05-19\n\n - change jwt.sign to return errors on callback instead of throwing errors ([1e46c5a42aa3dab8478efa4081d8f8f5c5485d56](https://github.com/auth0/node-jsonwebtoken/commit/1e46c5a42aa3dab8478efa4081d8f8f5c5485d56))\n\n## 6.2.0 - 2016-04-29\n\n - add support for `options.clockTolerance` to `jwt.verify` ([65ddea934f226bf06bc9d6a55be9587515cfc38d](https://github.com/auth0/node-jsonwebtoken/commit/65ddea934f226bf06bc9d6a55be9587515cfc38d))\n\n## 6.1.2 - 2016-04-29\n\n - fix sign method for node.js 0.12. closes #193 ([9c38374142d3929be3c9314b5e9bc5d963c5955f](https://github.com/auth0/node-jsonwebtoken/commit/9c38374142d3929be3c9314b5e9bc5d963c5955f)), closes [#193](https://github.com/auth0/node-jsonwebtoken/issues/193)\n - improve async test ([7b0981380ddc40a5f1208df520631785b5ffb85a](https://github.com/auth0/node-jsonwebtoken/commit/7b0981380ddc40a5f1208df520631785b5ffb85a))\n\n## 6.1.0 - 2016-04-27\n\n - verify unsigned tokens ([ec880791c10ed5ef7c8df7bf28ebb95c810479ed](https://github.com/auth0/node-jsonwebtoken/commit/ec880791c10ed5ef7c8df7bf28ebb95c810479ed))\n\n## 6.0.1 - 2016-04-27\n\nThis was an immediate change after publishing 6.0.0.\n\n - throw error on invalid options when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))\n\n## 6.0.0 - 2016-04-27\n\n - Change .sign to standard async callback ([50873c7d45d2733244d5da8afef3d1872e657a60](https://github.com/auth0/node-jsonwebtoken/commit/50873c7d45d2733244d5da8afef3d1872e657a60))\n - Improved the options for the `sign` method ([53c3987b3cc34e95eb396b26fc9b051276e2f6f9](https://github.com/auth0/node-jsonwebtoken/commit/53c3987b3cc34e95eb396b26fc9b051276e2f6f9))\n\n    -  throw error on invalid options like `expiresIn` when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))\n    -  `expiresInMinutes` and `expiresInSeconds` are deprecated and no longer supported.\n    -  `notBeforeInMinutes` and `notBeforeInSeconds` are deprecated and no longer supported.\n    -  `options` are strongly validated.\n    -  `options.expiresIn`, `options.notBefore`, `options.audience`, `options.issuer`, `options.subject` and `options.jwtid` are mutually exclusive with `payload.exp`, `payload.nbf`, `payload.aud`, `payload.iss`\n    -  `options.algorithm` is properly validated.\n    -  `options.headers` is renamed to `options.header`.\n\n - update CHANGELOG to reflect most of the changes. closes #136 ([b87a1a8d2e2533fbfab518765a54f00077918eb7](https://github.com/auth0/node-jsonwebtoken/commit/b87a1a8d2e2533fbfab518765a54f00077918eb7)), closes [#136](https://github.com/auth0/node-jsonwebtoken/issues/136)\n - update readme ([53a88ecf4494e30e1d62a1cf3cc354650349f486](https://github.com/auth0/node-jsonwebtoken/commit/53a88ecf4494e30e1d62a1cf3cc354650349f486))\n\n## 5.7.0 - 2016-02-16\n\n\n - add support for validating multiples issuers. closes #163 ([39d9309ae05648dbd72e5fd1993df064ad0e8fa5](https://github.com/auth0/node-jsonwebtoken/commit/39d9309ae05648dbd72e5fd1993df064ad0e8fa5)), closes [#163](https://github.com/auth0/node-jsonwebtoken/issues/163)\n\n\n## 5.6.1 - 2016-02-16\n\n\n - 5.6.1 ([06d8209d499dbc9a8dd978ab6cbb9c6818fde203](https://github.com/auth0/node-jsonwebtoken/commit/06d8209d499dbc9a8dd978ab6cbb9c6818fde203))\n - fix wrong error when setting expiration on non-object payload. closes #153 ([7f7d76edfd918d6afc7c7cead888caa42ccaceb4](https://github.com/auth0/node-jsonwebtoken/commit/7f7d76edfd918d6afc7c7cead888caa42ccaceb4)), closes [#153](https://github.com/auth0/node-jsonwebtoken/issues/153)\n\n\n\n## 5.6.0 - 2016-02-16\n\n\n - added missing validations of sub and jti ([a1affe960d0fc52e9042bcbdedb65734f8855580](https://github.com/auth0/node-jsonwebtoken/commit/a1affe960d0fc52e9042bcbdedb65734f8855580))\n - Fix tests in jwt.rs.tests.js which causes 4 to fail ([8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1](https://github.com/auth0/node-jsonwebtoken/commit/8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1))\n - Update README.md ([349b7cd00229789b138928ca060d3ef015aedaf9](https://github.com/auth0/node-jsonwebtoken/commit/349b7cd00229789b138928ca060d3ef015aedaf9))\n\n\n\n## 5.5.4 - 2016-01-04\n\n\n - minor ([46552e7c45025c76e3f647680d7539a66bfac612](https://github.com/auth0/node-jsonwebtoken/commit/46552e7c45025c76e3f647680d7539a66bfac612))\n\n\n\n## 5.5.3 - 2016-01-04\n\n\n - add a console.warn on invalid options for string payloads ([71200f14deba0533d3261266348338fac2d14661](https://github.com/auth0/node-jsonwebtoken/commit/71200f14deba0533d3261266348338fac2d14661))\n - minor ([65b1f580382dc58dd3da6f47a52713776fd7cdf2](https://github.com/auth0/node-jsonwebtoken/commit/65b1f580382dc58dd3da6f47a52713776fd7cdf2))\n\n\n\n## 5.5.2 - 2016-01-04\n\n\n - fix signing method with sealed objects, do not modify the params object. closes #147 ([be9c09af83b09c9e72da8b2c6166fa51d92aeab6](https://github.com/auth0/node-jsonwebtoken/commit/be9c09af83b09c9e72da8b2c6166fa51d92aeab6)), closes [#147](https://github.com/auth0/node-jsonwebtoken/issues/147)\n\n\n\n## 5.5.1 - 2016-01-04\n\n\n - fix nbf verification. fix #152 ([786d37b299c67771b5e71a2ca476666ab0f97d98](https://github.com/auth0/node-jsonwebtoken/commit/786d37b299c67771b5e71a2ca476666ab0f97d98)), closes [#152](https://github.com/auth0/node-jsonwebtoken/issues/152)\n\n\n\n## 5.5.0 - 2015-12-28\n\n\n - improvements to nbf and jti claims ([46372e928f6d2e7398f9b88022ca617d2a3b0699](https://github.com/auth0/node-jsonwebtoken/commit/46372e928f6d2e7398f9b88022ca617d2a3b0699))\n - Remove duplicate payload line (fix bug in IE strict mode) ([8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8](https://github.com/auth0/node-jsonwebtoken/commit/8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8))\n - Remove duplicate require('ms') line ([7c00bcbcbf8f7503a1070b394a165eccd41de66f](https://github.com/auth0/node-jsonwebtoken/commit/7c00bcbcbf8f7503a1070b394a165eccd41de66f))\n - Update README to reflect addition of async sign ([d661d4b6f68eb417834c99b36769444723041ccf](https://github.com/auth0/node-jsonwebtoken/commit/d661d4b6f68eb417834c99b36769444723041ccf))\n\n\n\n## 5.4.0 - 2015-10-02\n\n\n - deprecate expireInMinutes and expireInSeconds - in favor of expiresIn ([39ecc6f8f310f8462e082f1d53de0b4222b29b6f](https://github.com/auth0/node-jsonwebtoken/commit/39ecc6f8f310f8462e082f1d53de0b4222b29b6f))\n\n\n## 5.3.0 - 2015-10-02\n\n\n - 5.3.0 ([5d559ced3fbf10c1adae2e5792deda06ea89bcd3](https://github.com/auth0/node-jsonwebtoken/commit/5d559ced3fbf10c1adae2e5792deda06ea89bcd3))\n - minor ([6e81ff87a3799b0e56db09cbae42a97e784716c4](https://github.com/auth0/node-jsonwebtoken/commit/6e81ff87a3799b0e56db09cbae42a97e784716c4))\n\n\n\n## 5.1.0 - 2015-10-02\n\n\n - added async signing ([9414fbcb15a1f9cf4fe147d070e9424c547dabba](https://github.com/auth0/node-jsonwebtoken/commit/9414fbcb15a1f9cf4fe147d070e9424c547dabba))\n - Update README.md ([40b2aaaa843442dfb8ee7b574f0a788177e7c904](https://github.com/auth0/node-jsonwebtoken/commit/40b2aaaa843442dfb8ee7b574f0a788177e7c904))\n\n\n\n## 5.0.5 - 2015-08-19\n\n\n - add ms dep to package.json ([f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251](https://github.com/auth0/node-jsonwebtoken/commit/f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251))\n - add note to explain, related to #96 #101 #6 ([dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3](https://github.com/auth0/node-jsonwebtoken/commit/dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3))\n - add tests for options.headers ([7787dd74e705787c39a871ca29c75a2e0a3948ac](https://github.com/auth0/node-jsonwebtoken/commit/7787dd74e705787c39a871ca29c75a2e0a3948ac))\n - add tests for verify expires ([d7c5793d98c300603440ab460c11665f661ad3a0](https://github.com/auth0/node-jsonwebtoken/commit/d7c5793d98c300603440ab460c11665f661ad3a0))\n - add verify option maxAge (with tests) ([49d54e54f7e70b1c53a2e4ee67e116c907d75319](https://github.com/auth0/node-jsonwebtoken/commit/49d54e54f7e70b1c53a2e4ee67e116c907d75319))\n - fix spelling error in error message ([8078b11b224fa05ac9003ca5aa2c85e9f0128cfb](https://github.com/auth0/node-jsonwebtoken/commit/8078b11b224fa05ac9003ca5aa2c85e9f0128cfb))\n - Fix typo options.header is not a documented option + ([5feaa5b962ccbddeff054817a410f7b0c1e6ce7f](https://github.com/auth0/node-jsonwebtoken/commit/5feaa5b962ccbddeff054817a410f7b0c1e6ce7f))\n - update JWT spec link. closes #112 ([f5fa50f797456a12240589161835c7ea30807195](https://github.com/auth0/node-jsonwebtoken/commit/f5fa50f797456a12240589161835c7ea30807195)), closes [#112](https://github.com/auth0/node-jsonwebtoken/issues/112)\n\n\n## 5.0.3 - 2015-07-15\n\n - Added nbf support ([f26ba4e2fa197a20497632b63ffcd13ae93aacc4](https://github.com/auth0/node-jsonwebtoken/commit/f26ba4e2fa197a20497632b63ffcd13ae93aacc4))\n - Added support for subject and jwt id ([ab76ec5bc554e2d1e25376ddb7cea711d86af651](https://github.com/auth0/node-jsonwebtoken/commit/ab76ec5bc554e2d1e25376ddb7cea711d86af651))\n - Fix `this` referring to the global object instead of `module.exports` in `verify()` ([93f554312e37129027fcf4916f48cb8d1b53588c](https://github.com/auth0/node-jsonwebtoken/commit/93f554312e37129027fcf4916f48cb8d1b53588c))\n - Fix typo, line 139 README, complete option for .decode. ([59c110aeb8c7c1847ef2ffd77702d13627c89e10](https://github.com/auth0/node-jsonwebtoken/commit/59c110aeb8c7c1847ef2ffd77702d13627c89e10))\n - minor ([61ff1172272b582902313e958058ff22413494af](https://github.com/auth0/node-jsonwebtoken/commit/61ff1172272b582902313e958058ff22413494af))\n\n\n\n## 5.0.2 - 2015-06-15\n\n\n - fix typo in docs . closes #86 ([3d3413221f36acef4dfd1cbed87f1f3565cd6f84](https://github.com/auth0/node-jsonwebtoken/commit/3d3413221f36acef4dfd1cbed87f1f3565cd6f84)), closes [#86](https://github.com/auth0/node-jsonwebtoken/issues/86)\n\n\n\n## 5.0.1 - 2015-05-15\n\n\n - Add option to return header and payload when decoding. ([7254e011b59f892d1947e6c11819281adac7069d](https://github.com/auth0/node-jsonwebtoken/commit/7254e011b59f892d1947e6c11819281adac7069d))\n - Avoid uncaught \"SyntaxError: Unexpected token ͧ\" error. ([0dc59cd6ee15d83a606acffa7909ee76176ae186](https://github.com/auth0/node-jsonwebtoken/commit/0dc59cd6ee15d83a606acffa7909ee76176ae186))\n - Document complete option in README. ([ec32b20241a74d9681ea26e1a7024b4642468c00](https://github.com/auth0/node-jsonwebtoken/commit/ec32b20241a74d9681ea26e1a7024b4642468c00))\n - Fix example in README, silence verbose logging. ([ba3174d10033c41e9c211a38f1cc67f74fbd7f69](https://github.com/auth0/node-jsonwebtoken/commit/ba3174d10033c41e9c211a38f1cc67f74fbd7f69))\n - Fix link to auth0.com in README ([1b3c5ff72c9bc25e9271646e679f3080f2a042a0](https://github.com/auth0/node-jsonwebtoken/commit/1b3c5ff72c9bc25e9271646e679f3080f2a042a0))\n - Immediate return if not decoded. ([851bda2b10168f3269c3da6e74d310742f31a193](https://github.com/auth0/node-jsonwebtoken/commit/851bda2b10168f3269c3da6e74d310742f31a193))\n - Prevent throw on undefined/null secret ([0fdf78d4dbf609455f3277d6169a987aef0384d4](https://github.com/auth0/node-jsonwebtoken/commit/0fdf78d4dbf609455f3277d6169a987aef0384d4))\n - Removed path from test ([d6240e24186732d368bffe21143becf44c38f0d6](https://github.com/auth0/node-jsonwebtoken/commit/d6240e24186732d368bffe21143becf44c38f0d6))\n - Simplified checking for missing key ([f1cffd033bffc44f20558eda4a797c3fa2f4ee05](https://github.com/auth0/node-jsonwebtoken/commit/f1cffd033bffc44f20558eda4a797c3fa2f4ee05))\n - Typo ([ffe68dbe0219bab535c1018448eb4c0b22f1f902](https://github.com/auth0/node-jsonwebtoken/commit/ffe68dbe0219bab535c1018448eb4c0b22f1f902))\n - Update CHANGELOG.md ([927cce0dad1bc9aad75aeef53e276cf4cfc0d776](https://github.com/auth0/node-jsonwebtoken/commit/927cce0dad1bc9aad75aeef53e276cf4cfc0d776))\n - Update CHANGELOG.md ([6879e0fdde222995c70a3a69a4af94993d9c667e](https://github.com/auth0/node-jsonwebtoken/commit/6879e0fdde222995c70a3a69a4af94993d9c667e))\n - Update CHANGELOG.md ([c5596c10e8705727fa13e0394184a606083078bc](https://github.com/auth0/node-jsonwebtoken/commit/c5596c10e8705727fa13e0394184a606083078bc))\n - Update CHANGELOG.md ([07541f0315f26d179e1cde92732b6124d6869b6f](https://github.com/auth0/node-jsonwebtoken/commit/07541f0315f26d179e1cde92732b6124d6869b6f))\n - Update CHANGELOG.md ([e6465d48ddd1dc2c3297229b28c78fd5490a2ba9](https://github.com/auth0/node-jsonwebtoken/commit/e6465d48ddd1dc2c3297229b28c78fd5490a2ba9))\n\n## [5.0.0] - 2015-04-11\n\n### Changed\n\n - [sign] Only set defautl `iat` if the user does not specify that argument.\n\n  https://github.com/auth0/node-jsonwebtoken/commit/e900282a8d2dff1d4dec815f7e6aa7782e867d91\n  https://github.com/auth0/node-jsonwebtoken/commit/35036b188b4ee6b42df553bbb93bc8a6b19eae9d\n  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9\n  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e\n  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516\n\n### Security\n\n - [verify] Update to jws@^3.0.0 and renaming `header.alg` mismatch exception to `invalid algorithm` and adding more mismatch tests.\n\n  As `jws@3.0.0` changed the verify method signature to be `jws.verify(signature, algorithm, secretOrKey)`, the token header must be decoded first in order to make sure that the `alg` field matches one of the allowed `options.algorithms`. After that, the now validated `header.alg` is passed to `jws.verify`\n\n As the order of steps has changed, the error that was thrown when the JWT was invalid is no longer the `jws` one:\n ```\n { [Error: Invalid token: no header in signature 'a.b.c'] code: 'MISSING_HEADER', signature: 'a.b.c' }\n ```\n\n That old error (removed from jws) has been replaced by a `JsonWebTokenError` with message `invalid token`.\n\n > Important: versions >= 4.2.2 this library are safe to use but we decided to deprecate everything `< 5.0.0` to prevent security warnings from library `node-jws` when doing `npm install`.\n\n  https://github.com/auth0/node-jsonwebtoken/commit/634b8ed0ff5267dc25da5c808634208af109824e\n  https://github.com/auth0/node-jsonwebtoken/commit/9f24ffd5791febb449d4d03ff58d7807da9b9b7e\n  https://github.com/auth0/node-jsonwebtoken/commit/19e6cc6a1f2fd90356f89b074223b9665f2aa8a2\n  https://github.com/auth0/node-jsonwebtoken/commit/1e4623420159c6410616f02a44ed240f176287a9\n  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9\n  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e\n  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516\n\n## [4.2.2] - 2015-03-26\n### Fixed\n\n - [asymmetric-keys] Fix verify for RSAPublicKey formated keys (`jfromaniello - awlayton`)\n  https://github.com/auth0/node-jsonwebtoken/commit/402794663b9521bf602fcc6f2e811e7d3912f9dc\n  https://github.com/auth0/node-jsonwebtoken/commit/8df6aabbc7e1114c8fb3917931078254eb52c222\n\n## [4.2.1] - 2015-03-17\n### Fixed\n\n - [asymmetric-keys] Fixed issue when public key starts with BEING PUBLIC KEY (https://github.com/auth0/node-jsonwebtoken/issues/70) (`jfromaniello`)\n  https://github.com/auth0/node-jsonwebtoken/commit/7017e74db9b194448ff488b3e16468ada60c4ee5\n\n## [4.2.0] - 2015-03-16\n### Security\n\n - [asymmetric-keys] Making sure a token signed with an asymmetric key will be verified using a asymmetric key.\n   When the verification part was expecting a token digitally signed with an asymmetric key (RS/ES family) of algorithms an attacker could send a token signed with a symmetric algorithm (HS* family).\n\n  The issue was caused because the same signature was used to verify both type of tokens (`verify` method parameter: `secretOrPublicKey`).\n\n  This change adds a new parameter to the verify called `algorithms`. This can be used to specify a list of supported algorithms, but the default value depends on the secret used: if the secretOrPublicKey contains the string `BEGIN CERTIFICATE` the default is `[ 'RS256','RS384','RS512','ES256','ES384','ES512' ]` otherwise is `[ 'HS256','HS384','HS512' ]`. (`jfromaniello`)\n  https://github.com/auth0/node-jsonwebtoken/commit/c2bf7b2cd7e8daf66298c2d168a008690bc4bdd3\n  https://github.com/auth0/node-jsonwebtoken/commit/1bb584bc382295eeb7ee8c4452a673a77a68b687\n\n## [4.1.0] - 2015-03-10\n### Changed\n- Assume the payload is JSON even when there is no `typ` property. [5290db1](https://github.com/auth0/node-jsonwebtoken/commit/5290db1bd74f74cd38c90b19e2355ef223a4d931)\n\n## [4.0.0] - 2015-03-06\n### Changed\n- The default encoding is now utf8 instead of binary. [92d33bd](https://github.com/auth0/node-jsonwebtoken/commit/92d33bd99a3416e9e5a8897d9ad8ff7d70a00bfd)\n- Add `encoding` as a new option to `sign`. [1fc385e](https://github.com/auth0/node-jsonwebtoken/commit/1fc385ee10bd0018cd1441552dce6c2e5a16375f)\n- Add `ignoreExpiration` to `verify`. [8d4da27](https://github.com/auth0/node-jsonwebtoken/commit/8d4da279e1b351ac71ace276285c9255186d549f)\n- Add `expiresInSeconds` to `sign`. [dd156cc](https://github.com/auth0/node-jsonwebtoken/commit/dd156cc30f17028744e60aec0502897e34609329)\n\n### Fixed\n- Fix wrong error message when the audience doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)\n- Fix wrong error message when the issuer doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)\n- Fix wrong `iat` and `exp` values when signing with `noTimestamp`. [331b7bc](https://github.com/auth0/node-jsonwebtoken/commit/331b7bc9cc335561f8806f2c4558e105cb53e0a6)\n"
  },
  {
    "path": "CODEOWNERS",
    "content": "* @auth0/project-iam-protocols-engineer-codeowner\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n \nCopyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)\n \nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n \nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n \nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# jsonwebtoken\n\n| **Build**                                                                                                                               | **Dependency**                                                                                                         |\n|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|\n| [![Build Status](https://secure.travis-ci.org/auth0/node-jsonwebtoken.svg?branch=master)](http://travis-ci.org/auth0/node-jsonwebtoken) | [![Dependency Status](https://david-dm.org/auth0/node-jsonwebtoken.svg)](https://david-dm.org/auth0/node-jsonwebtoken) |\n\n\nAn implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519).\n\nThis was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws)\n\n# Install\n\n```bash\n$ npm install jsonwebtoken\n```\n\n# Migration notes\n\n* [From v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)\n* [From v7 to v8](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)\n\n# Usage\n\n### jwt.sign(payload, secretOrPrivateKey, [options, callback])\n\n(Asynchronous) If a callback is supplied, the callback is called with the `err` or the JWT.\n\n(Synchronous) Returns the JsonWebToken as string\n\n`payload` could be an object literal, buffer or string representing valid JSON. \n> **Please _note_ that** `exp` or any other claim is only set if the payload is an object literal. Buffer or string payloads are not checked for JSON validity.\n\n> If `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`.\n\n`secretOrPrivateKey` is a string (utf-8 encoded), buffer, object, or KeyObject containing either the secret for HMAC algorithms or the PEM\nencoded private key for RSA and ECDSA. In case of a private key with passphrase an object `{ key, passphrase }` can be used (based on [crypto documentation](https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format)), in this case be sure you pass the `algorithm` option.\nWhen signing with RSA algorithms the minimum modulus length is 2048 except when the allowInsecureKeySizes option is set to true. Private keys below this size will be rejected with an error.\n\n`options`:\n\n* `algorithm` (default: `HS256`)\n* `expiresIn`: expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms). \n  > Eg: `60`, `\"2 days\"`, `\"10h\"`, `\"7d\"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`\"120\"` is equal to `\"120ms\"`).\n* `notBefore`: expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms). \n  > Eg: `60`, `\"2 days\"`, `\"10h\"`, `\"7d\"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`\"120\"` is equal to `\"120ms\"`).\n* `audience`\n* `issuer`\n* `jwtid`\n* `subject`\n* `noTimestamp`\n* `header`\n* `keyid`\n* `mutatePayload`: if true, the sign function will modify the payload object directly. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token.\n* `allowInsecureKeySizes`: if true allows private keys with a modulus below 2048 to be used for RSA\n* `allowInvalidAsymmetricKeyTypes`: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.\n\n\n\n> There are no default values for `expiresIn`, `notBefore`, `audience`, `subject`, `issuer`.  These claims can also be provided in the payload directly with `exp`, `nbf`, `aud`, `sub` and `iss` respectively, but you **_can't_** include in both places.\n\nRemember that `exp`, `nbf` and `iat` are **NumericDate**, see related [Token Expiration (exp claim)](#token-expiration-exp-claim)\n\n\nThe header can be customized via the `options.header` object.\n\nGenerated jwts will include an `iat` (issued at) claim by default unless `noTimestamp` is specified. If `iat` is inserted in the payload, it will be used instead of the real timestamp for calculating other things like `exp` given a timespan in `options.expiresIn`.\n\nSynchronous Sign with default (HMAC SHA256)\n\n```js\nvar jwt = require('jsonwebtoken');\nvar token = jwt.sign({ foo: 'bar' }, 'shhhhh');\n```\n\nSynchronous Sign with RSA SHA256\n```js\n// sign with RSA SHA256\nvar privateKey = fs.readFileSync('private.key');\nvar token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });\n```\n\nSign asynchronously\n```js\njwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) {\n  console.log(token);\n});\n```\n\nBackdate a jwt 30 seconds\n```js\nvar older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');\n```\n\n#### Token Expiration (exp claim)\n\nThe standard for JWT defines an `exp` claim for expiration. The expiration is represented as a **NumericDate**:\n\n> A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds.  This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition \"Seconds Since the Epoch\", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented.  See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.\n\nThis means that the `exp` field should contain the number of seconds since the epoch.\n\nSigning a token with 1 hour of expiration:\n\n```javascript\njwt.sign({\n  exp: Math.floor(Date.now() / 1000) + (60 * 60),\n  data: 'foobar'\n}, 'secret');\n```\n\nAnother way to generate a token like this with this library is:\n\n```javascript\njwt.sign({\n  data: 'foobar'\n}, 'secret', { expiresIn: 60 * 60 });\n\n//or even better:\n\njwt.sign({\n  data: 'foobar'\n}, 'secret', { expiresIn: '1h' });\n```\n\n### jwt.verify(token, secretOrPublicKey, [options, callback])\n\n(Asynchronous) If a callback is supplied, function acts asynchronously. The callback is called with the decoded payload if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will be called with the error.\n\n(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will throw the error.\n\n> __Warning:__ When the token comes from an untrusted source (e.g. user input or external requests), the returned decoded payload should be treated like any other user input; please make sure to sanitize and only work with properties that are expected\n\n`token` is the JsonWebToken string\n\n`secretOrPublicKey` is a string (utf-8 encoded), buffer, or KeyObject containing either the secret for HMAC algorithms, or the PEM\nencoded public key for RSA and ECDSA.\nIf `jwt.verify` is called asynchronous, `secretOrPublicKey` can be a function that should fetch the secret or public key. See below for a detailed example\n\nAs mentioned in [this comment](https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138), there are other libraries that expect base64 encoded secrets (random bytes encoded using base64), if that is your case you can pass `Buffer.from(secret, 'base64')`, by doing this the secret will be decoded using base64 and the token verification will use the original random bytes.\n\n`options`\n\n* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `[\"HS256\", \"HS384\"]`. \n  > If not specified a defaults will be used based on the type of key provided\n  > * secret - ['HS256', 'HS384', 'HS512']\n  > * rsa - ['RS256', 'RS384', 'RS512']\n  > * ec - ['ES256', 'ES384', 'ES512']\n  > * default - ['RS256', 'RS384', 'RS512']\n* `audience`: if you want to check audience (`aud`), provide a value here. The audience can be checked against a string, a regular expression or a list of strings and/or regular expressions. \n  > Eg: `\"urn:foo\"`, `/urn:f[o]{2}/`, `[/urn:f[o]{2}/, \"urn:bar\"]`\n* `complete`: return an object with the decoded `{ payload, header, signature }` instead of only the usual content of the payload.\n* `issuer` (optional): string or array of strings of valid values for the `iss` field.\n* `jwtid` (optional): if you want to check JWT ID (`jti`), provide a string value here.\n* `ignoreExpiration`: if `true` do not validate the expiration of the token.\n* `ignoreNotBefore`...\n* `subject`: if you want to check subject (`sub`), provide a value here\n* `clockTolerance`: number of seconds to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers\n* `maxAge`: the maximum allowed age for tokens to still be valid. It is expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms). \n  > Eg: `1000`, `\"2 days\"`, `\"10h\"`, `\"7d\"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`\"120\"` is equal to `\"120ms\"`).\n* `clockTimestamp`: the time in seconds that should be used as the current time for all necessary comparisons.\n* `nonce`: if you want to check `nonce` claim, provide a string value here. It is used on Open ID for the ID Tokens. ([Open ID implementation notes](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes))\n* `allowInvalidAsymmetricKeyTypes`: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.\n\n```js\n// verify a token symmetric - synchronous\nvar decoded = jwt.verify(token, 'shhhhh');\nconsole.log(decoded.foo) // bar\n\n// verify a token symmetric\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  console.log(decoded.foo) // bar\n});\n\n// invalid token - synchronous\ntry {\n  var decoded = jwt.verify(token, 'wrong-secret');\n} catch(err) {\n  // err\n}\n\n// invalid token\njwt.verify(token, 'wrong-secret', function(err, decoded) {\n  // err\n  // decoded undefined\n});\n\n// verify a token asymmetric\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, function(err, decoded) {\n  console.log(decoded.foo) // bar\n});\n\n// verify audience\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {\n  // if audience mismatch, err == invalid audience\n});\n\n// verify issuer\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {\n  // if issuer mismatch, err == invalid issuer\n});\n\n// verify jwt id\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {\n  // if jwt id mismatch, err == invalid jwt id\n});\n\n// verify subject\nvar cert = fs.readFileSync('public.pem');  // get public key\njwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {\n  // if subject mismatch, err == invalid subject\n});\n\n// alg mismatch\nvar cert = fs.readFileSync('public.pem'); // get public key\njwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {\n  // if token alg != RS256,  err == invalid signature\n});\n\n// Verify using getKey callback\n// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys.\nvar jwksClient = require('jwks-rsa');\nvar client = jwksClient({\n  jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'\n});\nfunction getKey(header, callback){\n  client.getSigningKey(header.kid, function(err, key) {\n    var signingKey = key.publicKey || key.rsaPublicKey;\n    callback(null, signingKey);\n  });\n}\n\njwt.verify(token, getKey, options, function(err, decoded) {\n  console.log(decoded.foo) // bar\n});\n\n```\n\n<details>\n<summary><em></em>Need to peek into a JWT without verifying it? (Click to expand)</summary>\n\n### jwt.decode(token [, options])\n\n(Synchronous) Returns the decoded payload without verifying if the signature is valid.\n\n> __Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `jwt.verify` instead.\n\n> __Warning:__ When the token comes from an untrusted source (e.g. user input or external request), the returned decoded payload should be treated like any other user input; please make sure to sanitize and only work with properties that are expected\n\n\n`token` is the JsonWebToken string\n\n`options`:\n\n* `json`: force JSON.parse on the payload even if the header doesn't contain `\"typ\":\"JWT\"`.\n* `complete`: return an object with the decoded payload and header.\n\nExample\n\n```js\n// get the decoded payload ignoring signature, no secretOrPrivateKey needed\nvar decoded = jwt.decode(token);\n\n// get the decoded payload and header\nvar decoded = jwt.decode(token, {complete: true});\nconsole.log(decoded.header);\nconsole.log(decoded.payload)\n```\n\n</details>\n\n## Errors & Codes\nPossible thrown errors during verification.\nError is the first argument of the verification callback.\n\n### TokenExpiredError\n\nThrown error if the token is expired.\n\nError object:\n\n* name: 'TokenExpiredError'\n* message: 'jwt expired'\n* expiredAt: [ExpDate]\n\n```js\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  if (err) {\n    /*\n      err = {\n        name: 'TokenExpiredError',\n        message: 'jwt expired',\n        expiredAt: 1408621000\n      }\n    */\n  }\n});\n```\n\n### JsonWebTokenError\nError object:\n\n* name: 'JsonWebTokenError'\n* message:\n  * 'invalid token' - the header or payload could not be parsed\n  * 'jwt malformed' - the token does not have three components (delimited by a `.`)\n  * 'jwt signature is required'\n  * 'invalid signature'\n  * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'\n  * 'jwt issuer invalid. expected: [OPTIONS ISSUER]'\n  * 'jwt id invalid. expected: [OPTIONS JWT ID]'\n  * 'jwt subject invalid. expected: [OPTIONS SUBJECT]'\n\n```js\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  if (err) {\n    /*\n      err = {\n        name: 'JsonWebTokenError',\n        message: 'jwt malformed'\n      }\n    */\n  }\n});\n```\n\n### NotBeforeError\nThrown if current time is before the nbf claim.\n\nError object:\n\n* name: 'NotBeforeError'\n* message: 'jwt not active'\n* date: 2018-10-04T16:10:44.000Z\n\n```js\njwt.verify(token, 'shhhhh', function(err, decoded) {\n  if (err) {\n    /*\n      err = {\n        name: 'NotBeforeError',\n        message: 'jwt not active',\n        date: 2018-10-04T16:10:44.000Z\n      }\n    */\n  }\n});\n```\n\n\n## Algorithms supported\n\nArray of supported algorithms. The following algorithms are currently supported.\n\n| alg Parameter Value | Digital Signature or MAC Algorithm                                     |\n|---------------------|------------------------------------------------------------------------|\n| HS256               | HMAC using SHA-256 hash algorithm                                      |\n| HS384               | HMAC using SHA-384 hash algorithm                                      |\n| HS512               | HMAC using SHA-512 hash algorithm                                      |\n| RS256               | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm                         |\n| RS384               | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm                         |\n| RS512               | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm                         |\n| PS256               | RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0) |\n| PS384               | RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0) |\n| PS512               | RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0) |\n| ES256               | ECDSA using P-256 curve and SHA-256 hash algorithm                     |\n| ES384               | ECDSA using P-384 curve and SHA-384 hash algorithm                     |\n| ES512               | ECDSA using P-521 curve and SHA-512 hash algorithm                     |\n| none                | No digital signature or MAC value included                             |\n\n## Refreshing JWTs\n\nFirst of all, we recommend you to think carefully if auto-refreshing a JWT will not introduce any vulnerability in your system.\n\nWe are not comfortable including this as part of the library, however, you can take a look at [this example](https://gist.github.com/ziluvatar/a3feb505c4c0ec37059054537b38fc48) to show how this could be accomplished.\nApart from that example there are [an issue](https://github.com/auth0/node-jsonwebtoken/issues/122) and [a pull request](https://github.com/auth0/node-jsonwebtoken/pull/172) to get more knowledge about this topic.\n\n# TODO\n\n* X.509 certificate chain is not checked\n\n## Issue Reporting\n\nIf you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.\n\n## Author\n\n[Auth0](https://auth0.com)\n\n## License\n\nThis project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.\n"
  },
  {
    "path": "bin/changelog",
    "content": "#!/usr/bin/env node\n\nvar changelog = require('conventional-changelog');\nvar semver_regex = /\\bv?(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\\.[\\da-z\\-]+)*)?\\b/ig;\n\nconst commitPartial = ` - {{header}}\n\n{{~!-- commit hash --}} {{#if @root.linkReferences}}([{{hash}}]({{#if @root.host}}{{@root.host}}/{{/if}}{{#if @root.owner}}{{@root.owner}}/{{/if}}{{@root.repository}}/{{@root.commit}}/{{hash}})){{else}}{{hash~}}{{/if}}\n\n{{~!-- commit references --}}{{#if references}}, closes{{~#each references}} {{#if @root.linkReferences}}[{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}#{{this.issue}}]({{#if @root.host}}{{@root.host}}/{{/if}}{{#if this.repository}}{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}{{else}}{{#if @root.owner}}{{@root.owner}}/{{/if}}{{@root.repository}}{{/if}}/{{@root.issue}}/{{this.issue}}){{else}}{{#if this.owner}}{{this.owner}}/{{/if}}{{this.repository}}#{{this.issue}}{{/if}}{{/each}}{{/if}}\n`;\n\nconst headerPartial = `## {{version}}{{#if title}} \"{{title}}\"{{/if}}{{#if date}} - {{date}}{{/if}}\n`;\n\nchangelog({\n  releaseCount: 19,\n  // preset: 'jshint'\n}, null, null, null, {\n  transform: function (commit) {\n    if (commit.header && semver_regex.exec(commit.header)) {\n      return null;\n    }\n    return commit;\n  },\n  commitPartial: commitPartial,\n  headerPartial: headerPartial\n}).pipe(process.stdout);\n"
  },
  {
    "path": "decode.js",
    "content": "var jws = require('jws');\n\nmodule.exports = function (jwt, options) {\n  options = options || {};\n  var decoded = jws.decode(jwt, options);\n  if (!decoded) { return null; }\n  var payload = decoded.payload;\n\n  //try parse the payload\n  if(typeof payload === 'string') {\n    try {\n      var obj = JSON.parse(payload);\n      if(obj !== null && typeof obj === 'object') {\n        payload = obj;\n      }\n    } catch (e) { }\n  }\n\n  //return header if `complete` option is enabled.  header includes claims\n  //such as `kid` and `alg` used to select the key within a JWKS needed to\n  //verify the signature\n  if (options.complete === true) {\n    return {\n      header: decoded.header,\n      payload: payload,\n      signature: decoded.signature\n    };\n  }\n  return payload;\n};\n"
  },
  {
    "path": "index.js",
    "content": "module.exports = {\n  decode: require('./decode'),\n  verify: require('./verify'),\n  sign: require('./sign'),\n  JsonWebTokenError: require('./lib/JsonWebTokenError'),\n  NotBeforeError: require('./lib/NotBeforeError'),\n  TokenExpiredError: require('./lib/TokenExpiredError'),\n};\n"
  },
  {
    "path": "lib/JsonWebTokenError.js",
    "content": "var JsonWebTokenError = function (message, error) {\n  Error.call(this, message);\n  if(Error.captureStackTrace) {\n    Error.captureStackTrace(this, this.constructor);\n  }\n  this.name = 'JsonWebTokenError';\n  this.message = message;\n  if (error) this.inner = error;\n};\n\nJsonWebTokenError.prototype = Object.create(Error.prototype);\nJsonWebTokenError.prototype.constructor = JsonWebTokenError;\n\nmodule.exports = JsonWebTokenError;\n"
  },
  {
    "path": "lib/NotBeforeError.js",
    "content": "var JsonWebTokenError = require('./JsonWebTokenError');\n\nvar NotBeforeError = function (message, date) {\n  JsonWebTokenError.call(this, message);\n  this.name = 'NotBeforeError';\n  this.date = date;\n};\n\nNotBeforeError.prototype = Object.create(JsonWebTokenError.prototype);\n\nNotBeforeError.prototype.constructor = NotBeforeError;\n\nmodule.exports = NotBeforeError;"
  },
  {
    "path": "lib/TokenExpiredError.js",
    "content": "var JsonWebTokenError = require('./JsonWebTokenError');\n\nvar TokenExpiredError = function (message, expiredAt) {\n  JsonWebTokenError.call(this, message);\n  this.name = 'TokenExpiredError';\n  this.expiredAt = expiredAt;\n};\n\nTokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype);\n\nTokenExpiredError.prototype.constructor = TokenExpiredError;\n\nmodule.exports = TokenExpiredError;"
  },
  {
    "path": "lib/asymmetricKeyDetailsSupported.js",
    "content": "const semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '>=15.7.0');\n"
  },
  {
    "path": "lib/psSupported.js",
    "content": "var semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '^6.12.0 || >=8.0.0');\n"
  },
  {
    "path": "lib/rsaPssKeyDetailsSupported.js",
    "content": "const semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '>=16.9.0');\n"
  },
  {
    "path": "lib/timespan.js",
    "content": "var ms = require('ms');\n\nmodule.exports = function (time, iat) {\n  var timestamp = iat || Math.floor(Date.now() / 1000);\n\n  if (typeof time === 'string') {\n    var milliseconds = ms(time);\n    if (typeof milliseconds === 'undefined') {\n      return;\n    }\n    return Math.floor(timestamp + milliseconds / 1000);\n  } else if (typeof time === 'number') {\n    return timestamp + time;\n  } else {\n    return;\n  }\n\n};"
  },
  {
    "path": "lib/validateAsymmetricKey.js",
    "content": "const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('./asymmetricKeyDetailsSupported');\nconst RSA_PSS_KEY_DETAILS_SUPPORTED = require('./rsaPssKeyDetailsSupported');\n\nconst allowedAlgorithmsForKeys = {\n  'ec': ['ES256', 'ES384', 'ES512'],\n  'rsa': ['RS256', 'PS256', 'RS384', 'PS384', 'RS512', 'PS512'],\n  'rsa-pss': ['PS256', 'PS384', 'PS512']\n};\n\nconst allowedCurves = {\n  ES256: 'prime256v1',\n  ES384: 'secp384r1',\n  ES512: 'secp521r1',\n};\n\nmodule.exports = function(algorithm, key) {\n  if (!algorithm || !key) return;\n\n  const keyType = key.asymmetricKeyType;\n  if (!keyType) return;\n\n  const allowedAlgorithms = allowedAlgorithmsForKeys[keyType];\n\n  if (!allowedAlgorithms) {\n    throw new Error(`Unknown key type \"${keyType}\".`);\n  }\n\n  if (!allowedAlgorithms.includes(algorithm)) {\n    throw new Error(`\"alg\" parameter for \"${keyType}\" key type must be one of: ${allowedAlgorithms.join(', ')}.`)\n  }\n\n  /*\n   * Ignore the next block from test coverage because it gets executed\n   * conditionally depending on the Node version. Not ignoring it would\n   * prevent us from reaching the target % of coverage for versions of\n   * Node under 15.7.0.\n   */\n  /* istanbul ignore next */\n  if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {\n    switch (keyType) {\n    case 'ec':\n      const keyCurve = key.asymmetricKeyDetails.namedCurve;\n      const allowedCurve = allowedCurves[algorithm];\n\n      if (keyCurve !== allowedCurve) {\n        throw new Error(`\"alg\" parameter \"${algorithm}\" requires curve \"${allowedCurve}\".`);\n      }\n      break;\n\n    case 'rsa-pss':\n      if (RSA_PSS_KEY_DETAILS_SUPPORTED) {\n        const length = parseInt(algorithm.slice(-3), 10);\n        const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;\n\n        if (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm) {\n          throw new Error(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of \"alg\" ${algorithm}.`);\n        }\n\n        if (saltLength !== undefined && saltLength > length >> 3) {\n          throw new Error(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of \"alg\" ${algorithm}.`)\n        }\n      }\n      break;\n    }\n  }\n}\n"
  },
  {
    "path": "opslevel.yml",
    "content": "---\nversion: 1\nrepository:\n  owner: iam_protocols\n  tier:\n  tags:\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"jsonwebtoken\",\n  \"version\": \"9.0.3\",\n  \"description\": \"JSON Web Token implementation (symmetric and asymmetric)\",\n  \"main\": \"index.js\",\n  \"nyc\": {\n    \"check-coverage\": true,\n    \"lines\": 95,\n    \"statements\": 95,\n    \"functions\": 100,\n    \"branches\": 95,\n    \"exclude\": [\n      \"./test/**\"\n    ],\n    \"reporter\": [\n      \"json\",\n      \"lcov\",\n      \"text-summary\"\n    ]\n  },\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"coverage\": \"nyc mocha --use_strict\",\n    \"test\": \"mocha\",\n    \"prepare\": \"husky\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/auth0/node-jsonwebtoken\"\n  },\n  \"keywords\": [\n    \"jwt\"\n  ],\n  \"author\": \"auth0\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/auth0/node-jsonwebtoken/issues\"\n  },\n  \"dependencies\": {\n    \"jws\": \"^4.0.1\",\n    \"lodash.includes\": \"^4.3.0\",\n    \"lodash.isboolean\": \"^3.0.3\",\n    \"lodash.isinteger\": \"^4.0.4\",\n    \"lodash.isnumber\": \"^3.0.3\",\n    \"lodash.isplainobject\": \"^4.0.6\",\n    \"lodash.isstring\": \"^4.0.1\",\n    \"lodash.once\": \"^4.0.0\",\n    \"ms\": \"^2.1.1\",\n    \"semver\": \"^7.5.4\"\n  },\n  \"devDependencies\": {\n    \"@commitlint/cli\": \"^20.3.1\",\n    \"@commitlint/config-conventional\": \"^20.3.1\",\n    \"@semantic-release/exec\": \"^7.0.3\",\n    \"atob\": \"^2.1.2\",\n    \"chai\": \"^4.1.2\",\n    \"conventional-changelog\": \"~1.1.0\",\n    \"eslint\": \"^4.19.1\",\n    \"husky\": \"^9.1.7\",\n    \"mocha\": \"^5.2.0\",\n    \"nsp\": \"^2.6.2\",\n    \"nyc\": \"^11.9.0\",\n    \"semantic-release\": \"^25.0.2\",\n    \"sinon\": \"^6.0.0\"\n  },\n  \"engines\": {\n    \"npm\": \">=6\",\n    \"node\": \">=12\"\n  },\n  \"files\": [\n    \"lib\",\n    \"decode.js\",\n    \"sign.js\",\n    \"verify.js\"\n  ]\n}\n"
  },
  {
    "path": "sign.js",
    "content": "const timespan = require('./lib/timespan');\nconst PS_SUPPORTED = require('./lib/psSupported');\nconst validateAsymmetricKey = require('./lib/validateAsymmetricKey');\nconst jws = require('jws');\nconst includes = require('lodash.includes');\nconst isBoolean = require('lodash.isboolean');\nconst isInteger = require('lodash.isinteger');\nconst isNumber = require('lodash.isnumber');\nconst isPlainObject = require('lodash.isplainobject');\nconst isString = require('lodash.isstring');\nconst once = require('lodash.once');\nconst { KeyObject, createSecretKey, createPrivateKey } = require('crypto')\n\nconst SUPPORTED_ALGS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'none'];\nif (PS_SUPPORTED) {\n  SUPPORTED_ALGS.splice(3, 0, 'PS256', 'PS384', 'PS512');\n}\n\nconst sign_options_schema = {\n  expiresIn: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '\"expiresIn\" should be a number of seconds or string representing a timespan' },\n  notBefore: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '\"notBefore\" should be a number of seconds or string representing a timespan' },\n  audience: { isValid: function(value) { return isString(value) || Array.isArray(value); }, message: '\"audience\" must be a string or array' },\n  algorithm: { isValid: includes.bind(null, SUPPORTED_ALGS), message: '\"algorithm\" must be a valid string enum value' },\n  header: { isValid: isPlainObject, message: '\"header\" must be an object' },\n  encoding: { isValid: isString, message: '\"encoding\" must be a string' },\n  issuer: { isValid: isString, message: '\"issuer\" must be a string' },\n  subject: { isValid: isString, message: '\"subject\" must be a string' },\n  jwtid: { isValid: isString, message: '\"jwtid\" must be a string' },\n  noTimestamp: { isValid: isBoolean, message: '\"noTimestamp\" must be a boolean' },\n  keyid: { isValid: isString, message: '\"keyid\" must be a string' },\n  mutatePayload: { isValid: isBoolean, message: '\"mutatePayload\" must be a boolean' },\n  allowInsecureKeySizes: { isValid: isBoolean, message: '\"allowInsecureKeySizes\" must be a boolean'},\n  allowInvalidAsymmetricKeyTypes: { isValid: isBoolean, message: '\"allowInvalidAsymmetricKeyTypes\" must be a boolean'}\n};\n\nconst registered_claims_schema = {\n  iat: { isValid: isNumber, message: '\"iat\" should be a number of seconds' },\n  exp: { isValid: isNumber, message: '\"exp\" should be a number of seconds' },\n  nbf: { isValid: isNumber, message: '\"nbf\" should be a number of seconds' }\n};\n\nfunction validate(schema, allowUnknown, object, parameterName) {\n  if (!isPlainObject(object)) {\n    throw new Error('Expected \"' + parameterName + '\" to be a plain object.');\n  }\n  Object.keys(object)\n    .forEach(function(key) {\n      const validator = schema[key];\n      if (!validator) {\n        if (!allowUnknown) {\n          throw new Error('\"' + key + '\" is not allowed in \"' + parameterName + '\"');\n        }\n        return;\n      }\n      if (!validator.isValid(object[key])) {\n        throw new Error(validator.message);\n      }\n    });\n}\n\nfunction validateOptions(options) {\n  return validate(sign_options_schema, false, options, 'options');\n}\n\nfunction validatePayload(payload) {\n  return validate(registered_claims_schema, true, payload, 'payload');\n}\n\nconst options_to_payload = {\n  'audience': 'aud',\n  'issuer': 'iss',\n  'subject': 'sub',\n  'jwtid': 'jti'\n};\n\nconst options_for_objects = [\n  'expiresIn',\n  'notBefore',\n  'noTimestamp',\n  'audience',\n  'issuer',\n  'subject',\n  'jwtid',\n];\n\nmodule.exports = function (payload, secretOrPrivateKey, options, callback) {\n  if (typeof options === 'function') {\n    callback = options;\n    options = {};\n  } else {\n    options = options || {};\n  }\n\n  const isObjectPayload = typeof payload === 'object' &&\n                        !Buffer.isBuffer(payload);\n\n  const header = Object.assign({\n    alg: options.algorithm || 'HS256',\n    typ: isObjectPayload ? 'JWT' : undefined,\n    kid: options.keyid\n  }, options.header);\n\n  function failure(err) {\n    if (callback) {\n      return callback(err);\n    }\n    throw err;\n  }\n\n  if (!secretOrPrivateKey && options.algorithm !== 'none') {\n    return failure(new Error('secretOrPrivateKey must have a value'));\n  }\n\n  if (secretOrPrivateKey != null && !(secretOrPrivateKey instanceof KeyObject)) {\n    try {\n      secretOrPrivateKey = createPrivateKey(secretOrPrivateKey)\n    } catch (_) {\n      try {\n        secretOrPrivateKey = createSecretKey(typeof secretOrPrivateKey === 'string' ? Buffer.from(secretOrPrivateKey) : secretOrPrivateKey)\n      } catch (_) {\n        return failure(new Error('secretOrPrivateKey is not valid key material'));\n      }\n    }\n  }\n\n  if (header.alg.startsWith('HS') && secretOrPrivateKey.type !== 'secret') {\n    return failure(new Error((`secretOrPrivateKey must be a symmetric key when using ${header.alg}`)))\n  } else if (/^(?:RS|PS|ES)/.test(header.alg)) {\n    if (secretOrPrivateKey.type !== 'private') {\n      return failure(new Error((`secretOrPrivateKey must be an asymmetric key when using ${header.alg}`)))\n    }\n    if (!options.allowInsecureKeySizes &&\n      !header.alg.startsWith('ES') &&\n      secretOrPrivateKey.asymmetricKeyDetails !== undefined && //KeyObject.asymmetricKeyDetails is supported in Node 15+\n      secretOrPrivateKey.asymmetricKeyDetails.modulusLength < 2048) {\n      return failure(new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`));\n    }\n  }\n\n  if (typeof payload === 'undefined') {\n    return failure(new Error('payload is required'));\n  } else if (isObjectPayload) {\n    try {\n      validatePayload(payload);\n    }\n    catch (error) {\n      return failure(error);\n    }\n    if (!options.mutatePayload) {\n      payload = Object.assign({},payload);\n    }\n  } else {\n    const invalid_options = options_for_objects.filter(function (opt) {\n      return typeof options[opt] !== 'undefined';\n    });\n\n    if (invalid_options.length > 0) {\n      return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload'));\n    }\n  }\n\n  if (typeof payload.exp !== 'undefined' && typeof options.expiresIn !== 'undefined') {\n    return failure(new Error('Bad \"options.expiresIn\" option the payload already has an \"exp\" property.'));\n  }\n\n  if (typeof payload.nbf !== 'undefined' && typeof options.notBefore !== 'undefined') {\n    return failure(new Error('Bad \"options.notBefore\" option the payload already has an \"nbf\" property.'));\n  }\n\n  try {\n    validateOptions(options);\n  }\n  catch (error) {\n    return failure(error);\n  }\n\n  if (!options.allowInvalidAsymmetricKeyTypes) {\n    try {\n      validateAsymmetricKey(header.alg, secretOrPrivateKey);\n    } catch (error) {\n      return failure(error);\n    }\n  }\n\n  const timestamp = payload.iat || Math.floor(Date.now() / 1000);\n\n  if (options.noTimestamp) {\n    delete payload.iat;\n  } else if (isObjectPayload) {\n    payload.iat = timestamp;\n  }\n\n  if (typeof options.notBefore !== 'undefined') {\n    try {\n      payload.nbf = timespan(options.notBefore, timestamp);\n    }\n    catch (err) {\n      return failure(err);\n    }\n    if (typeof payload.nbf === 'undefined') {\n      return failure(new Error('\"notBefore\" should be a number of seconds or string representing a timespan eg: \"1d\", \"20h\", 60'));\n    }\n  }\n\n  if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') {\n    try {\n      payload.exp = timespan(options.expiresIn, timestamp);\n    }\n    catch (err) {\n      return failure(err);\n    }\n    if (typeof payload.exp === 'undefined') {\n      return failure(new Error('\"expiresIn\" should be a number of seconds or string representing a timespan eg: \"1d\", \"20h\", 60'));\n    }\n  }\n\n  Object.keys(options_to_payload).forEach(function (key) {\n    const claim = options_to_payload[key];\n    if (typeof options[key] !== 'undefined') {\n      if (typeof payload[claim] !== 'undefined') {\n        return failure(new Error('Bad \"options.' + key + '\" option. The payload already has an \"' + claim + '\" property.'));\n      }\n      payload[claim] = options[key];\n    }\n  });\n\n  const encoding = options.encoding || 'utf8';\n\n  if (typeof callback === 'function') {\n    callback = callback && once(callback);\n\n    jws.createSign({\n      header: header,\n      privateKey: secretOrPrivateKey,\n      payload: payload,\n      encoding: encoding\n    }).once('error', callback)\n      .once('done', function (signature) {\n        // TODO: Remove in favor of the modulus length check before signing once node 15+ is the minimum supported version\n        if(!options.allowInsecureKeySizes && /^(?:RS|PS)/.test(header.alg) && signature.length < 256) {\n          return callback(new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`))\n        }\n        callback(null, signature);\n      });\n  } else {\n    let signature = jws.sign({header: header, payload: payload, secret: secretOrPrivateKey, encoding: encoding});\n    // TODO: Remove in favor of the modulus length check before signing once node 15+ is the minimum supported version\n    if(!options.allowInsecureKeySizes && /^(?:RS|PS)/.test(header.alg) && signature.length < 256) {\n      throw new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`)\n    }\n    return signature\n  }\n};\n"
  },
  {
    "path": "test/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"mocha\": true\n  }\n}\n"
  },
  {
    "path": "test/async_sign.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar jws = require('jws');\nvar PS_SUPPORTED = require('../lib/psSupported');\nconst {generateKeyPairSync} = require(\"crypto\");\n\ndescribe('signing a token asynchronously', function() {\n\n  describe('when signing a token', function() {\n    var secret = 'shhhhhh';\n\n    it('should return the same result as singing synchronously', function(done) {\n      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' }, function (err, asyncToken) {\n        if (err) return done(err);\n        var syncToken = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });\n        expect(asyncToken).to.be.a('string');\n        expect(asyncToken.split('.')).to.have.length(3);\n        expect(asyncToken).to.equal(syncToken);\n        done();\n      });\n    });\n\n    it('should work with empty options', function (done) {\n      jwt.sign({abc: 1}, \"secret\", {}, function (err) {\n        expect(err).to.be.null;\n        done();\n      });\n    });\n\n    it('should work without options object at all', function (done) {\n      jwt.sign({abc: 1}, \"secret\", function (err) {\n        expect(err).to.be.null;\n        done();\n      });\n    });\n\n    it('should work with none algorithm where secret is set', function(done) {\n      jwt.sign({ foo: 'bar' }, 'secret', { algorithm: 'none' }, function(err, token) {\n        expect(token).to.be.a('string');\n        expect(token.split('.')).to.have.length(3);\n        done();\n      });\n    });\n\n    //Known bug: https://github.com/brianloveswords/node-jws/issues/62\n    //If you need this use case, you need to go for the non-callback-ish code style.\n    it.skip('should work with none algorithm where secret is falsy', function(done) {\n      jwt.sign({ foo: 'bar' }, undefined, { algorithm: 'none' }, function(err, token) {\n        expect(token).to.be.a('string');\n        expect(token.split('.')).to.have.length(3);\n        done();\n      });\n    });\n\n    it('should return error when secret is not a cert for RS256', function(done) {\n      //this throw an error because the secret is not a cert and RS256 requires a cert.\n      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'RS256' }, function (err) {\n        expect(err).to.be.ok;\n        done();\n      });\n    });\n\n    it('should not work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is false or not set', function(done) {\n      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });\n\n      jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function (err) {\n        expect(err).to.be.ok;\n        done();\n      });\n    });\n\n    it('should work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is true', function(done) {\n      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });\n\n      jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256', allowInsecureKeySizes: true }, done);\n    });\n\n    if (PS_SUPPORTED) {\n      it('should return error when secret is not a cert for PS256', function(done) {\n        //this throw an error because the secret is not a cert and PS256 requires a cert.\n        jwt.sign({ foo: 'bar' }, secret, { algorithm: 'PS256' }, function (err) {\n          expect(err).to.be.ok;\n          done();\n        });\n      });\n    }\n\n    it('should return error on wrong arguments', function(done) {\n      //this throw an error because the secret is not a cert and RS256 requires a cert.\n      jwt.sign({ foo: 'bar' }, secret, { notBefore: {} }, function (err) {\n        expect(err).to.be.ok;\n        done();\n      });\n    });\n\n    it('should return error on wrong arguments (2)', function(done) {\n      jwt.sign('string', 'secret', {noTimestamp: true}, function (err) {\n        expect(err).to.be.ok;\n        expect(err).to.be.instanceof(Error);\n        done();\n      });\n    });\n\n    it('should not stringify the payload', function (done) {\n      jwt.sign('string', 'secret', {}, function (err, token) {\n        if (err) { return done(err); }\n        expect(jws.decode(token).payload).to.equal('string');\n        done();\n      });\n    });\n\n    describe('when mutatePayload is not set', function() {\n      it('should not apply claims to the original payload object (mutatePayload defaults to false)', function(done) {\n        var originalPayload = { foo: 'bar' };\n        jwt.sign(originalPayload, 'secret', { notBefore: 60, expiresIn: 600 }, function (err) {\n          if (err) { return done(err); }\n          expect(originalPayload).to.not.have.property('nbf');\n          expect(originalPayload).to.not.have.property('exp');\n          done();\n        });\n      });\n    });\n\n    describe('when mutatePayload is set to true', function() {\n      it('should apply claims directly to the original payload object', function(done) {\n        var originalPayload = { foo: 'bar' };\n        jwt.sign(originalPayload, 'secret', { notBefore: 60, expiresIn: 600, mutatePayload: true }, function (err) {\n          if (err) { return done(err); }\n          expect(originalPayload).to.have.property('nbf').that.is.a('number');\n          expect(originalPayload).to.have.property('exp').that.is.a('number');\n          done();\n        });\n      });\n    });\n\n    describe('secret must have a value', function(){\n      [undefined, '', 0].forEach(function(secret){\n        it('should return an error if the secret is falsy and algorithm is not set to none: ' + (typeof secret === 'string' ? '(empty string)' : secret), function(done) {\n        // This is needed since jws will not answer for falsy secrets\n          jwt.sign('string', secret, {}, function(err, token) {\n            expect(err).to.exist;\n            expect(err.message).to.equal('secretOrPrivateKey must have a value');\n            expect(token).to.not.exist;\n            done();\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/buffer.tests.js",
    "content": "var jwt = require(\"../.\");\nvar assert = require('chai').assert;\n\ndescribe('buffer payload', function () {\n  it('should work', function () {\n    var payload = new Buffer('TkJyotZe8NFpgdfnmgINqg==', 'base64');\n    var token = jwt.sign(payload, \"signing key\");\n    assert.equal(jwt.decode(token), payload.toString());\n  });\n});\n"
  },
  {
    "path": "test/claim-aud.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithAudience(audience, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (audience !== undefined) {\n    options.audience = audience;\n  }\n\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\nfunction verifyWithAudience(token, audience,  callback) {\n  testUtils.verifyJWTHelper(token, 'secret', {audience}, callback);\n}\n\ndescribe('audience', function() {\n  describe('`jwt.sign` \"audience\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1,\n      1,\n      0,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      {},\n      {foo: 'bar'},\n    ].forEach((audience) => {\n      it(`should error with with value ${util.inspect(audience)}`, function (done) {\n        signWithAudience(audience, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"audience\" must be a string or array');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {aud: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {audience: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', '\"audience\" must be a string or array');\n        });\n      });\n    });\n\n    it('should error when \"aud\" is in payload', function (done) {\n      signWithAudience('my_aud', {aud: ''}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.audience\" option. The payload already has an \"aud\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function (done) {\n      signWithAudience('my_aud', 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid audience option for string payload');\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function (done) {\n      signWithAudience('my_aud', new Buffer('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid audience option for object payload');\n        });\n      });\n    });\n  });\n\n  describe('when signing and verifying a token with \"audience\" option', function () {\n    describe('with a \"aud\" of \"urn:foo\" in payload', function () {\n      let token;\n\n      beforeEach(function (done) {\n        signWithAudience('urn:foo', {}, (err, t) => {\n          token = t;\n          done(err);\n        });\n      });\n\n      [\n        undefined,\n        'urn:foo',\n        /^urn:f[o]{2}$/,\n        ['urn:no_match', 'urn:foo'],\n        ['urn:no_match', /^urn:f[o]{2}$/],\n        [/^urn:no_match$/, /^urn:f[o]{2}$/],\n        [/^urn:no_match$/, 'urn:foo']\n      ].forEach((audience) =>{\n        it(`should verify and decode with verify \"audience\" option of ${util.inspect(audience)}`, function (done) {\n          verifyWithAudience(token, audience, (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud', 'urn:foo');\n            });\n          });\n        });\n      });\n\n      it(`should error on no match with a string verify \"audience\" option`, function (done) {\n        verifyWithAudience(token, 'urn:no-match', (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);\n          });\n        });\n      });\n\n      it('should error on no match with an array of string verify \"audience\" option', function (done) {\n        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);\n          });\n        });\n      });\n\n      it('should error on no match with a Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, /^urn:no-match$/, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);\n          });\n        });\n      });\n\n      it('should error on no match with an array of Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property(\n              'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`\n            );\n          });\n        });\n      });\n\n      it('should error on no match with an array of a Regex and a string in verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property(\n              'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`\n            );\n          });\n        });\n      });\n    });\n\n    describe('with an array of [\"urn:foo\", \"urn:bar\"] for \"aud\" value in payload', function () {\n      let token;\n\n      beforeEach(function (done) {\n        signWithAudience(['urn:foo', 'urn:bar'], {}, (err, t) => {\n          token = t;\n          done(err);\n        });\n      });\n\n      [\n        undefined,\n        'urn:foo',\n        /^urn:f[o]{2}$/,\n        ['urn:no_match', 'urn:foo'],\n        ['urn:no_match', /^urn:f[o]{2}$/],\n        [/^urn:no_match$/, /^urn:f[o]{2}$/],\n        [/^urn:no_match$/, 'urn:foo']\n      ].forEach((audience) =>{\n        it(`should verify and decode with verify \"audience\" option of ${util.inspect(audience)}`, function (done) {\n          verifyWithAudience(token, audience, (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n      });\n\n      it(`should error on no match with a string verify \"audience\" option`, function (done) {\n        verifyWithAudience(token, 'urn:no-match', (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);\n          });\n        });\n      });\n\n      it('should error on no match with an array of string verify \"audience\" option', function (done) {\n        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);\n          });\n        });\n      });\n\n      it('should error on no match with a Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, /^urn:no-match$/, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);\n          });\n        });\n      });\n\n      it('should error on no match with an array of Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property(\n              'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`\n            );\n          });\n        });\n      });\n\n      it('should error on no match with an array of a Regex and a string in verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property(\n              'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`\n            );\n          });\n        });\n      });\n\n      describe('when checking for a matching on both \"urn:foo\" and \"urn:bar\"', function() {\n        it('should verify with an array of stings verify \"audience\" option', function (done) {\n          verifyWithAudience(token, ['urn:foo', 'urn:bar'], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with a Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, /^urn:[a-z]{3}$/, (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array of Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, [/^urn:f[o]{2}$/, /^urn:b[ar]{2}$/], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n      });\n\n      describe('when checking for a matching for \"urn:foo\"', function() {\n        it('should verify with a string verify \"audience\"', function (done) {\n          verifyWithAudience(token, 'urn:foo', (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with a Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, /^urn:f[o]{2}$/, (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array of Regex verify \"audience\"', function (done) {\n          verifyWithAudience(token, [/^urn:no-match$/, /^urn:f[o]{2}$/], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array containing a string and a Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, ['urn:no_match', /^urn:f[o]{2}$/], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array containing a Regex and a string verify \"audience\" option', function (done) {\n          verifyWithAudience(token, [/^urn:no-match$/, 'urn:foo'], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n      });\n\n      describe('when checking matching for \"urn:bar\"', function() {\n        it('should verify with a string verify \"audience\"', function (done) {\n          verifyWithAudience(token, 'urn:bar', (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with a Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, /^urn:b[ar]{2}$/, (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array of Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, [/^urn:no-match$/, /^urn:b[ar]{2}$/], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array containing a string and a Regex verify \"audience\" option', function (done) {\n          verifyWithAudience(token, ['urn:no_match', /^urn:b[ar]{2}$/], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n\n        it('should verify with an array containing a Regex and a string verify \"audience\" option', function (done) {\n          verifyWithAudience(token, [/^urn:no-match$/, 'urn:bar'], (err, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(err).to.be.null;\n              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);\n            });\n          });\n        });\n      });\n    });\n\n    describe('without a \"aud\" value in payload', function () {\n      let token;\n\n      beforeEach(function (done) {\n        signWithAudience(undefined, {}, (err, t) => {\n          token = t;\n          done(err);\n        });\n      });\n\n      it('should verify and decode without verify \"audience\" option', function (done) {\n        verifyWithAudience(token, undefined, (err, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.null;\n            expect(decoded).to.not.have.property('aud');\n          });\n        });\n      });\n\n      it('should error on no match with a string verify \"audience\" option', function (done) {\n        verifyWithAudience(token, 'urn:no-match', (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match');\n          });\n        });\n      });\n\n      it('should error on no match with an array of string verify \"audience\" option', function (done) {\n        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2');\n          });\n        });\n      });\n\n      it('should error on no match with a Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, /^urn:no-match$/, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/');\n          });\n        });\n      });\n\n      it('should error on no match with an array of Regex verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/');\n          });\n        });\n      });\n\n      it('should error on no match with an array of a Regex and a string in verify \"audience\" option', function (done) {\n        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match');\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-exp.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst util = require('util');\nconst testUtils = require('./test-utils');\nconst jws = require('jws');\n\nfunction signWithExpiresIn(expiresIn, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (expiresIn !== undefined) {\n    options.expiresIn = expiresIn;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('expires', function() {\n  describe('`jwt.sign` \"expiresIn\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      ' ',\n      '',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((expiresIn) => {\n      it(`should error with with value ${util.inspect(expiresIn)}`, function (done) {\n        signWithExpiresIn(expiresIn, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message')\n              .match(/\"expiresIn\" should be a number of seconds or string representing a timespan/);\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {expiresIn: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {expiresIn: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            '\"expiresIn\" should be a number of seconds or string representing a timespan'\n          );\n        });\n      });\n    });\n\n    it ('should error when \"exp\" is in payload', function(done) {\n      signWithExpiresIn(100, {exp: 100}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.expiresIn\" option the payload already has an \"exp\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function(done) {\n      signWithExpiresIn(100, 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid expiresIn option for string payload');\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function(done) {\n      signWithExpiresIn(100, Buffer.from('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid expiresIn option for object payload');\n        });\n      });\n    });\n  });\n\n  describe('`jwt.sign` \"exp\" claim validation', function () {\n    [\n      true,\n      false,\n      null,\n      undefined,\n      '',\n      ' ',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((exp) => {\n      it(`should error with with value ${util.inspect(exp)}`, function (done) {\n        signWithExpiresIn(undefined, {exp}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"exp\" should be a number of seconds');\n          });\n        });\n      });\n    });\n  });\n\n  describe('\"exp\" in payload validation', function () {\n    [\n      true,\n      false,\n      null,\n      -Infinity,\n      Infinity,\n      NaN,\n      '',\n      ' ',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((exp) => {\n      it(`should error with with value ${util.inspect(exp)}`, function (done) {\n        const header = { alg: 'HS256' };\n        const payload = { exp };\n        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });\n        testUtils.verifyJWTHelper(token, 'secret', { exp }, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'invalid exp value');\n          });\n        });\n      });\n    })\n  });\n\n  describe('when signing and verifying a token with expires option', function () {\n    let fakeClock;\n    beforeEach(function() {\n      fakeClock = sinon.useFakeTimers({now: 60000});\n    });\n\n    afterEach(function() {\n      fakeClock.uninstall();\n    });\n\n    it('should set correct \"exp\" with negative number of seconds', function(done) {\n      signWithExpiresIn(-10, {}, (e1, token) => {\n        fakeClock.tick(-10001);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 50);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"exp\" with positive number of seconds', function(done) {\n      signWithExpiresIn(10, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 70);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"exp\" with zero seconds', function(done) {\n      signWithExpiresIn(0, {}, (e1, token) => {\n        fakeClock.tick(-1);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 60);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"exp\" with negative string timespan', function(done) {\n      signWithExpiresIn('-10 s', {}, (e1, token) => {\n        fakeClock.tick(-10001);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 50);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"exp\" with positive string timespan', function(done) {\n      signWithExpiresIn('10 s', {}, (e1, token) => {\n        fakeClock.tick(-10001);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 70);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"exp\" with zero string timespan', function(done) {\n      signWithExpiresIn('0 s', {}, (e1, token) => {\n        fakeClock.tick(-1);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 60);\n          });\n        })\n      });\n    });\n\n    // TODO an exp of -Infinity should fail validation\n    it('should set null \"exp\" when given -Infinity', function (done) {\n      signWithExpiresIn(undefined, {exp: -Infinity}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('exp', null);\n        });\n      });\n    });\n\n    // TODO an exp of Infinity should fail validation\n    it('should set null \"exp\" when given value Infinity', function (done) {\n      signWithExpiresIn(undefined, {exp: Infinity}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('exp', null);\n        });\n      });\n    });\n\n    // TODO an exp of NaN should fail validation\n    it('should set null \"exp\" when given value NaN', function (done) {\n      signWithExpiresIn(undefined, {exp: NaN}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('exp', null);\n        });\n      });\n    });\n\n    it('should set correct \"exp\" when \"iat\" is passed', function (done) {\n      signWithExpiresIn(-10, {iat: 80}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('exp', 70);\n          });\n        })\n      });\n    });\n\n    it('should verify \"exp\" using \"clockTimestamp\"', function (done) {\n      signWithExpiresIn(10, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 69}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('exp', 70);\n          });\n        })\n      });\n    });\n\n    it('should verify \"exp\" using \"clockTolerance\"', function (done) {\n      signWithExpiresIn(5, {}, (e1, token) => {\n        fakeClock.tick(10000);\n        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 6}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('exp', 65);\n          });\n        })\n      });\n    });\n\n    it('should ignore a expired token when \"ignoreExpiration\" is true', function (done) {\n      signWithExpiresIn('-10 s', {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {ignoreExpiration: true}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('exp', 50);\n          });\n        })\n      });\n    });\n\n    it('should error on verify if \"exp\" is at current time', function(done) {\n      signWithExpiresIn(undefined, {exp: 60}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.TokenExpiredError);\n            expect(e2).to.have.property('message', 'jwt expired');\n          });\n        });\n      });\n    });\n\n    it('should error on verify if \"exp\" is before current time using clockTolerance', function (done) {\n      signWithExpiresIn(-5, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 5}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.TokenExpiredError);\n            expect(e2).to.have.property('message', 'jwt expired');\n          });\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-iat.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst util = require('util');\nconst testUtils = require('./test-utils');\nconst jws = require('jws');\n\nfunction signWithIssueAt(issueAt, options, callback) {\n  const payload = {};\n  if (issueAt !== undefined) {\n    payload.iat = issueAt;\n  }\n  const opts = Object.assign({algorithm: 'HS256'}, options);\n  // async calls require a truthy secret\n  // see: https://github.com/brianloveswords/node-jws/issues/62\n  testUtils.signJWTHelper(payload, 'secret', opts, callback);\n}\n\nfunction verifyWithIssueAt(token, maxAge, options, secret, callback) {\n  const opts = Object.assign({maxAge}, options);\n  testUtils.verifyJWTHelper(token, secret, opts, callback);\n}\n\ndescribe('issue at', function() {\n  describe('`jwt.sign` \"iat\" claim validation', function () {\n    [\n      true,\n      false,\n      null,\n      '',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((iat) => {\n      it(`should error with iat of ${util.inspect(iat)}`, function (done) {\n        signWithIssueAt(iat, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err.message).to.equal('\"iat\" should be a number of seconds');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {iat: undefined}\n    it('should error with iat of undefined', function (done) {\n      testUtils.signJWTHelper({iat: undefined}, 'secret', {algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err.message).to.equal('\"iat\" should be a number of seconds');\n        });\n      });\n    });\n  });\n\n  describe('\"iat\" in payload with \"maxAge\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      undefined,\n      -Infinity,\n      Infinity,\n      NaN,\n      '',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((iat) => {\n      it(`should error with iat of ${util.inspect(iat)}`, function (done) {\n        const header = { alg: 'HS256' };\n        const payload = { iat };\n        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });\n        verifyWithIssueAt(token, '1 min', {}, 'secret', (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err.message).to.equal('iat required when maxAge is specified');\n          });\n        });\n      });\n    })\n  });\n\n  describe('when signing a token', function () {\n    let fakeClock;\n    beforeEach(function () {\n      fakeClock = sinon.useFakeTimers({now: 60000});\n    });\n\n    afterEach(function () {\n      fakeClock.uninstall();\n    });\n\n    [\n      {\n        description: 'should default to current time for \"iat\"',\n        iat: undefined,\n        expectedIssueAt: 60,\n        options: {}\n      },\n      {\n        description: 'should sign with provided time for \"iat\"',\n        iat: 100,\n        expectedIssueAt: 100,\n        options: {}\n      },\n      // TODO an iat of -Infinity should fail validation\n      {\n        description: 'should set null \"iat\" when given -Infinity',\n        iat: -Infinity,\n        expectedIssueAt: null,\n        options: {}\n      },\n      // TODO an iat of Infinity should fail validation\n      {\n        description: 'should set null \"iat\" when given Infinity',\n        iat: Infinity,\n        expectedIssueAt: null,\n        options: {}\n      },\n      // TODO an iat of NaN should fail validation\n      {\n        description: 'should set to current time for \"iat\" when given value NaN',\n        iat: NaN,\n        expectedIssueAt: 60,\n        options: {}\n      },\n      {\n        description: 'should remove default \"iat\" with \"noTimestamp\" option',\n        iat: undefined,\n        expectedIssueAt: undefined,\n        options: {noTimestamp: true}\n      },\n      {\n        description: 'should remove provided \"iat\" with \"noTimestamp\" option',\n        iat: 10,\n        expectedIssueAt: undefined,\n        options: {noTimestamp: true}\n      },\n    ].forEach((testCase) => {\n      it(testCase.description, function (done) {\n        signWithIssueAt(testCase.iat, testCase.options, (err, token) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.null;\n            expect(jwt.decode(token).iat).to.equal(testCase.expectedIssueAt);\n          });\n        });\n      });\n    });\n  });\n\n  describe('when verifying a token', function() {\n    let fakeClock;\n\n    beforeEach(function() {\n      fakeClock = sinon.useFakeTimers({now: 60000});\n    });\n\n    afterEach(function () {\n      fakeClock.uninstall();\n    });\n\n    [\n      {\n        description: 'should verify using \"iat\" before the \"maxAge\"',\n        clockAdvance: 10000,\n        maxAge: 11,\n        options: {},\n      },\n      {\n        description: 'should verify using \"iat\" before the \"maxAge\" with a provided \"clockTimestamp',\n        clockAdvance: 60000,\n        maxAge: 11,\n        options: {clockTimestamp: 70},\n      },\n      {\n        description: 'should verify using \"iat\" after the \"maxAge\" but within \"clockTolerance\"',\n        clockAdvance: 10000,\n        maxAge: 9,\n        options: {clockTimestamp: 2},\n      },\n    ].forEach((testCase) => {\n      it(testCase.description, function (done) {\n        const token = jwt.sign({}, 'secret', {algorithm: 'HS256'});\n        fakeClock.tick(testCase.clockAdvance);\n        verifyWithIssueAt(token, testCase.maxAge, testCase.options, 'secret', (err, token) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.null;\n            expect(token).to.be.a('object');\n          });\n        });\n      });\n    });\n\n    [\n      {\n        description: 'should throw using \"iat\" equal to the \"maxAge\"',\n        clockAdvance: 10000,\n        maxAge: 10,\n        options: {},\n        expectedError: 'maxAge exceeded',\n        expectedExpiresAt: 70000,\n      },\n      {\n        description: 'should throw using \"iat\" after the \"maxAge\"',\n        clockAdvance: 10000,\n        maxAge: 9,\n        options: {},\n        expectedError: 'maxAge exceeded',\n        expectedExpiresAt: 69000,\n      },\n      {\n        description: 'should throw using \"iat\" after the \"maxAge\" with a provided \"clockTimestamp',\n        clockAdvance: 60000,\n        maxAge: 10,\n        options: {clockTimestamp: 70},\n        expectedError: 'maxAge exceeded',\n        expectedExpiresAt: 70000,\n      },\n      {\n        description: 'should throw using \"iat\" after the \"maxAge\" and \"clockTolerance',\n        clockAdvance: 10000,\n        maxAge: 8,\n        options: {clockTolerance: 2},\n        expectedError: 'maxAge exceeded',\n        expectedExpiresAt: 68000,\n      },\n    ].forEach((testCase) => {\n      it(testCase.description, function(done) {\n        const expectedExpiresAtDate = new Date(testCase.expectedExpiresAt);\n        const token = jwt.sign({}, 'secret', {algorithm: 'HS256'});\n        fakeClock.tick(testCase.clockAdvance);\n\n        verifyWithIssueAt(token, testCase.maxAge, testCase.options, 'secret', (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err.message).to.equal(testCase.expectedError);\n            expect(err.expiredAt).to.deep.equal(expectedExpiresAtDate);\n          });\n        });\n      });\n    });\n  });\n\n  describe('with string payload', function () {\n    it('should not add iat to string', function (done) {\n      const payload = 'string payload';\n      const options = {algorithm: 'HS256'};\n      testUtils.signJWTHelper(payload, 'secret', options, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.equal(payload);\n        });\n      });\n    });\n\n    it('should not add iat to stringified object', function (done) {\n      const payload = '{}';\n      const options = {algorithm: 'HS256', header: {typ: 'JWT'}};\n      testUtils.signJWTHelper(payload, 'secret', options, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.equal(null);\n          expect(JSON.stringify(decoded)).to.equal(payload);\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-iss.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithIssuer(issuer, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (issuer !== undefined) {\n    options.issuer = issuer;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('issuer', function() {\n  describe('`jwt.sign` \"issuer\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1,\n      0,\n      1,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((issuer) => {\n      it(`should error with with value ${util.inspect(issuer)}`, function (done) {\n        signWithIssuer(issuer, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"issuer\" must be a string');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {issuer: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {issuer: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', '\"issuer\" must be a string');\n        });\n      });\n    });\n\n    it('should error when \"iss\" is in payload', function (done) {\n      signWithIssuer('foo', {iss: 'bar'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.issuer\" option. The payload already has an \"iss\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function (done) {\n      signWithIssuer('foo', 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid issuer option for string payload'\n          );\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function (done) {\n      signWithIssuer('foo', new Buffer('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid issuer option for object payload'\n          );\n        });\n      });\n    });\n  });\n\n  describe('when signing and verifying a token', function () {\n    it('should not verify \"iss\" if verify \"issuer\" option not provided', function(done) {\n      signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iss', 'foo');\n          });\n        })\n      });\n    });\n\n    describe('with string \"issuer\" option', function () {\n      it('should verify with a string \"issuer\"', function (done) {\n        signWithIssuer('foo', {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('iss', 'foo');\n            });\n          })\n        });\n      });\n\n      it('should verify with a string \"iss\"', function (done) {\n        signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('iss', 'foo');\n            });\n          })\n        });\n      });\n\n      it('should error if \"iss\" does not match verify \"issuer\" option', function(done) {\n        signWithIssuer(undefined, {iss: 'foobar'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo');\n            });\n          })\n        });\n      });\n\n      it('should error without \"iss\" and with verify \"issuer\" option', function(done) {\n        signWithIssuer(undefined, {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo');\n            });\n          })\n        });\n      });\n    });\n\n    describe('with array \"issuer\" option', function () {\n      it('should verify with a string \"issuer\"', function (done) {\n        signWithIssuer('bar', {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('iss', 'bar');\n            });\n          })\n        });\n      });\n\n      it('should verify with a string \"iss\"', function (done) {\n        signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('iss', 'foo');\n            });\n          })\n        });\n      });\n\n      it('should error if \"iss\" does not match verify \"issuer\" option', function(done) {\n        signWithIssuer(undefined, {iss: 'foobar'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo,bar');\n            });\n          })\n        });\n      });\n\n      it('should error without \"iss\" and with verify \"issuer\" option', function(done) {\n        signWithIssuer(undefined, {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo,bar');\n            });\n          })\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-jti.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithJWTId(jwtid, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (jwtid !== undefined) {\n    options.jwtid = jwtid;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('jwtid', function() {\n  describe('`jwt.sign` \"jwtid\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1,\n      0,\n      1,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((jwtid) => {\n      it(`should error with with value ${util.inspect(jwtid)}`, function (done) {\n        signWithJWTId(jwtid, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"jwtid\" must be a string');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {jwtid: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {jwtid: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', '\"jwtid\" must be a string');\n        });\n      });\n    });\n\n    it('should error when \"jti\" is in payload', function (done) {\n      signWithJWTId('foo', {jti: 'bar'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.jwtid\" option. The payload already has an \"jti\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function (done) {\n      signWithJWTId('foo', 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid jwtid option for string payload'\n          );\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function (done) {\n      signWithJWTId('foo', new Buffer('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid jwtid option for object payload'\n          );\n        });\n      });\n    });\n  });\n\n  describe('when signing and verifying a token', function () {\n    it('should not verify \"jti\" if verify \"jwtid\" option not provided', function(done) {\n      signWithJWTId(undefined, {jti: 'foo'}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('jti', 'foo');\n          });\n        })\n      });\n    });\n\n    describe('with \"jwtid\" option', function () {\n      it('should verify with \"jwtid\" option', function (done) {\n        signWithJWTId('foo', {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('jti', 'foo');\n            });\n          })\n        });\n      });\n\n      it('should verify with \"jti\" in payload', function (done) {\n        signWithJWTId(undefined, {jti: 'foo'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {jetid: 'foo'}, (e2, decoded) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.null;\n              expect(decoded).to.have.property('jti', 'foo');\n            });\n          })\n        });\n      });\n\n      it('should error if \"jti\" does not match verify \"jwtid\" option', function(done) {\n        signWithJWTId(undefined, {jti: 'bar'}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt jwtid invalid. expected: foo');\n            });\n          })\n        });\n      });\n\n      it('should error without \"jti\" and with verify \"jwtid\" option', function(done) {\n        signWithJWTId(undefined, {}, (e1, token) => {\n          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2) => {\n            testUtils.asyncCheck(done, () => {\n              expect(e1).to.be.null;\n              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n              expect(e2).to.have.property('message', 'jwt jwtid invalid. expected: foo');\n            });\n          })\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-nbf.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst util = require('util');\nconst testUtils = require('./test-utils');\nconst jws = require('jws');\n\nfunction signWithNotBefore(notBefore, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (notBefore !== undefined) {\n    options.notBefore = notBefore;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('not before', function() {\n  describe('`jwt.sign` \"notBefore\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      '',\n      ' ',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((notBefore) => {\n      it(`should error with with value ${util.inspect(notBefore)}`, function (done) {\n        signWithNotBefore(notBefore, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message')\n              .match(/\"notBefore\" should be a number of seconds or string representing a timespan/);\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {notBefore: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {notBefore: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            '\"notBefore\" should be a number of seconds or string representing a timespan'\n          );\n        });\n      });\n    });\n\n    it('should error when \"nbf\" is in payload', function (done) {\n      signWithNotBefore(100, {nbf: 100}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.notBefore\" option the payload already has an \"nbf\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function (done) {\n      signWithNotBefore(100, 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid notBefore option for string payload');\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function (done) {\n      signWithNotBefore(100, new Buffer('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', 'invalid notBefore option for object payload');\n        });\n      });\n    });\n  });\n\n  describe('`jwt.sign` \"nbf\" claim validation', function () {\n    [\n      true,\n      false,\n      null,\n      undefined,\n      '',\n      ' ',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((nbf) => {\n      it(`should error with with value ${util.inspect(nbf)}`, function (done) {\n        signWithNotBefore(undefined, {nbf}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"nbf\" should be a number of seconds');\n          });\n        });\n      });\n    });\n  });\n\n  describe('\"nbf\" in payload validation', function () {\n    [\n      true,\n      false,\n      null,\n      -Infinity,\n      Infinity,\n      NaN,\n      '',\n      ' ',\n      'invalid',\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((nbf) => {\n      it(`should error with with value ${util.inspect(nbf)}`, function (done) {\n        const header = { alg: 'HS256' };\n        const payload = { nbf };\n        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });\n        testUtils.verifyJWTHelper(token, 'secret', {nbf}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(err).to.have.property('message', 'invalid nbf value');\n          });\n        });\n      });\n    })\n  });\n\n  describe('when signing and verifying a token with \"notBefore\" option', function () {\n    let fakeClock;\n    beforeEach(function () {\n      fakeClock = sinon.useFakeTimers({now: 60000});\n    });\n\n    afterEach(function () {\n      fakeClock.uninstall();\n    });\n\n    it('should set correct \"nbf\" with negative number of seconds', function (done) {\n      signWithNotBefore(-10, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 50);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"nbf\" with positive number of seconds', function (done) {\n      signWithNotBefore(10, {}, (e1, token) => {\n        fakeClock.tick(10000);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 70);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"nbf\" with zero seconds', function (done) {\n      signWithNotBefore(0, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 60);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"nbf\" with negative string timespan', function (done) {\n      signWithNotBefore('-10 s', {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 50);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"nbf\" with positive string timespan', function (done) {\n      signWithNotBefore('10 s', {}, (e1, token) => {\n        fakeClock.tick(10000);\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 70);\n          });\n        })\n      });\n    });\n\n    it('should set correct \"nbf\" with zero string timespan', function (done) {\n      signWithNotBefore('0 s', {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 60);\n          });\n        })\n      });\n    });\n\n    // TODO an nbf of -Infinity should fail validation\n    it('should set null \"nbf\" when given -Infinity', function (done) {\n      signWithNotBefore(undefined, {nbf: -Infinity}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('nbf', null);\n        });\n      });\n    });\n\n    // TODO an nbf of Infinity should fail validation\n    it('should set null \"nbf\" when given value Infinity', function (done) {\n      signWithNotBefore(undefined, {nbf: Infinity}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('nbf', null);\n        });\n      });\n    });\n\n    // TODO an nbf of NaN should fail validation\n    it('should set null \"nbf\" when given value NaN', function (done) {\n      signWithNotBefore(undefined, {nbf: NaN}, (err, token) => {\n        const decoded = jwt.decode(token);\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('nbf', null);\n        });\n      });\n    });\n\n    it('should set correct \"nbf\" when \"iat\" is passed', function (done) {\n      signWithNotBefore(-10, {iat: 40}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('nbf', 30);\n          });\n        })\n      });\n    });\n\n    it('should verify \"nbf\" using \"clockTimestamp\"', function (done) {\n      signWithNotBefore(10, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 70}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('nbf', 70);\n          });\n        })\n      });\n    });\n\n    it('should verify \"nbf\" using \"clockTolerance\"', function (done) {\n      signWithNotBefore(5, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 6}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('nbf', 65);\n          });\n        })\n      });\n    });\n\n    it('should ignore a not active token when \"ignoreNotBefore\" is true', function (done) {\n      signWithNotBefore('10 s', {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {ignoreNotBefore: true}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('iat', 60);\n            expect(decoded).to.have.property('nbf', 70);\n          });\n        })\n      });\n    });\n\n    it('should error on verify if \"nbf\" is after current time', function (done) {\n      signWithNotBefore(undefined, {nbf: 61}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.NotBeforeError);\n            expect(e2).to.have.property('message', 'jwt not active');\n          });\n        })\n      });\n    });\n\n    it('should error on verify if \"nbf\" is after current time using clockTolerance', function (done) {\n      signWithNotBefore(5, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 4}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.NotBeforeError);\n            expect(e2).to.have.property('message', 'jwt not active');\n          });\n        })\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-private.tests.js",
    "content": "'use strict';\n\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithPayload(payload, callback) {\n  testUtils.signJWTHelper(payload, 'secret', {algorithm: 'HS256'}, callback);\n}\n\ndescribe('with a private claim', function() {\n  [\n    true,\n    false,\n    null,\n    -1,\n    0,\n    1,\n    -1.1,\n    1.1,\n    '',\n    'private claim',\n    'UTF8 - José',\n    [],\n    ['foo'],\n    {},\n    {foo: 'bar'},\n  ].forEach((privateClaim) => {\n    it(`should sign and verify with claim of ${util.inspect(privateClaim)}`, function (done) {\n      signWithPayload({privateClaim}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('privateClaim').to.deep.equal(privateClaim);\n          });\n        })\n      });\n    });\n  });\n\n  // these values JSON.stringify to null\n  [\n    -Infinity,\n    Infinity,\n    NaN,\n  ].forEach((privateClaim) => {\n    it(`should sign and verify with claim of ${util.inspect(privateClaim)}`, function (done) {\n      signWithPayload({privateClaim}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('privateClaim', null);\n          });\n        })\n      });\n    });\n  });\n\n  // private claims with value undefined are not added to the payload\n  it(`should sign and verify with claim of undefined`, function (done) {\n    signWithPayload({privateClaim: undefined}, (e1, token) => {\n      testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n        testUtils.asyncCheck(done, () => {\n          expect(e1).to.be.null;\n          expect(e2).to.be.null;\n          expect(decoded).to.not.have.property('privateClaim');\n        });\n      })\n    });\n  });\n});\n"
  },
  {
    "path": "test/claim-sub.tests.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithSubject(subject, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (subject !== undefined) {\n    options.subject = subject;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('subject', function() {\n  describe('`jwt.sign` \"subject\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1,\n      0,\n      1,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((subject) => {\n      it(`should error with with value ${util.inspect(subject)}`, function (done) {\n        signWithSubject(subject, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"subject\" must be a string');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {subject: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {subject: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', '\"subject\" must be a string');\n        });\n      });\n    });\n\n    it('should error when \"sub\" is in payload', function (done) {\n      signWithSubject('foo', {sub: 'bar'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'Bad \"options.subject\" option. The payload already has an \"sub\" property.'\n          );\n        });\n      });\n    });\n\n    it('should error with a string payload', function (done) {\n      signWithSubject('foo', 'a string payload', (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid subject option for string payload'\n          );\n        });\n      });\n    });\n\n    it('should error with a Buffer payload', function (done) {\n      signWithSubject('foo', new Buffer('a Buffer payload'), (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property(\n            'message',\n            'invalid subject option for object payload'\n          );\n        });\n      });\n    });\n  });\n\n  describe('when signing and verifying a token with \"subject\" option', function () {\n    it('should verify with a string \"subject\"', function (done) {\n      signWithSubject('foo', {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('sub', 'foo');\n          });\n        })\n      });\n    });\n\n    it('should verify with a string \"sub\"', function (done) {\n      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('sub', 'foo');\n          });\n        })\n      });\n    });\n\n    it('should not verify \"sub\" if verify \"subject\" option not provided', function(done) {\n      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.null;\n            expect(decoded).to.have.property('sub', 'foo');\n          });\n        })\n      });\n    });\n\n    it('should error if \"sub\" does not match verify \"subject\" option', function(done) {\n      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {subject: 'bar'}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(e2).to.have.property('message', 'jwt subject invalid. expected: bar');\n          });\n        })\n      });\n    });\n\n    it('should error without \"sub\" and with verify \"subject\" option', function(done) {\n      signWithSubject(undefined, {}, (e1, token) => {\n        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2) => {\n          testUtils.asyncCheck(done, () => {\n            expect(e1).to.be.null;\n            expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);\n            expect(e2).to.have.property('message', 'jwt subject invalid. expected: foo');\n          });\n        })\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/decoding.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('decoding', function() {\n\n  it('should not crash when decoding a null token', function () {\n    var decoded = jwt.decode(\"null\");\n    expect(decoded).to.equal(null);\n  });\n\n});\n"
  },
  {
    "path": "test/dsa-private.pem",
    "content": "-----BEGIN DSA PRIVATE KEY-----\nMIIGWAIBAAKCAgEArzbPbt//BQpsYsnoZR4R9nXgcuvcXoH8WZjRsb4ZPfVJGchG\n7CfRMlG0HR34vcUpehNj5pAavErhfNnk1CEal0TyDsOkBY/+JG239zXgRzMYjSE6\nptX5kj5pGv0uXVoozSP/JZblI8/Spd6TZkblLNAYOl3ssfcUGN4NFDXlzmiWvP+q\n6ZUgE8tD7CSryicICKmXcVQIa6AG8ultYa6mBAaewzMbiIt2TUo9smglpEqGeHoL\nCuLb3e7zLf0AhWDZOgTTfe1KFEiK6TXMe9HWYeP3MPuyKhS20GmT/Zcu5VN4wbr0\nbP+mTWk700oLJ0OPQ6YgGkyqBmh/Bsi/TqnpJWS/mjRbJEe3E2NmNMwmP4jwJ79V\nJClp5Gg9kbM6hPkmGNnhbbFzn3kwY3pi9/AiqpGyr3GUPhXvP7fYwAu/A5ISKw8r\n87j/EJntyIzm51fcm8Q0mq1IDt4tNkIOwJEIc45h9r7ZC1VAKkzlCa7XT04GguFo\nJMaJBYESYcOAmbKRojo8P/cN4fPuemuhQFQplkFIM6FtG9cJMo2ayp6ukH9Up8tn\n8j7YgE/m9BL9SnUIbNlti9j0cNgeKVn24WC38hw9D8M0/sR5gYyclWh/OotCttoQ\nI8ySZzSvB4GARZHbexagvg1EdV93ctYyAWGLkpJYAzuiXbt7FayG7e2ifYkCIQDp\nIldsAFGVaiJRQdiKsWdReOSjzH6h8cw6Co3OCISiOQKCAgEAnSU29U65jK3W2BiA\nfKTlTBx2yDUCDFeqnla5arZ2njGsUKiP2nocArAPLQggwk9rfqufybQltM8+zjmE\nzeb4mUCVhSbTH7BvP903U0YEabZJCHLx80nTywq2RgQs0Qmn43vs2U5EidYR0xj8\nCCNAH5gdzd9/CL1RYACHAf7zj4n68ZaNkAy9Jz1JjYXjP6IAxJh1W/Y0vsdFdIJ/\ndnuxsyMCUCSwDvSNApSfATO/tw+DCVpGgKo4qE8b8lsfXKeihuMzyXuSe/D98YN2\nUFWRTQ6gFxGrntg3LOn41RXSkXxzixgl7quacIJzm8jrFkDJSx4AZ8rgt/9JbThA\nXF9PVlCVv7GL1NztUs4cDK+zsJld4O1rlI3QOz5DWq9oA+Hj1MN3L9IW3Iv2Offo\nAaubXJhuv0xPWYmtCo06mPgSwkWPjDnGCbp1vuI8zPTsfyhsahuKeW0h8JttW4GB\n6CTtC1AVWA1pJug5pBo36S5G24ihRsdG3Q5/aTlnke7t7H1Tkh2KuvV9hD5a5Xtw\ncnuiEcKjyR0FWR81RdsAKh+7QNI3Lx75c95i22Aupon5R/Qkb05VzHdd299bb78c\nx5mW8Dsg4tKLF7kpDAcWmx7JpkPHQ+5V9N766sfZ+z/PiVWfNAK8gzJRn/ceLQcK\nC6uOhcZgN0o4UYrmYEy9icxJ44wCggIBAIu+yagyVMS+C5OqOprmtteh/+MyaYI+\nQ3oPXFR8eHLJftsBWev1kRfje1fdxzzx/k4SQMRbxxbMtGV74KNwRUzEWOkoyAHP\nAAjhMio1mxknPwAxRjWDOSE0drGJPyGpI9ZfpMUtvekQO7MCGqa45vPldY10RwZC\nVN66AIpxSF0MG1OEmgD+noHMI7moclw/nw+ZUPaIFxvPstlD4EsPDkdE0I6x3k3b\nUXlWAYAJFR6fNf8+Ki3xnjLjW9da3cU/p2H7+LrFDP+kPUGJpqr4bG606GUcV3Cl\ndznoqlgaudWgcQCQx0NPzi7k5O7PXr7C3UU0cg+5+GkviIzogaioxidvvchnG+UU\n0y5nVuji6G69j5sUhlcFXte31Nte2VUb6P8umo+mbDT0UkZZZzoOsCpw+cJ8OHOV\nemFIhVphNHqQt20Tq6WVRBx+p4+YNWiThvmLtmLh0QghdnUrJZxyXx7/p8K5SE9/\n+qU11t5dUvYS+53U1gJ2kgIFO4Zt6gaoOyexTt5f4Ganh9IcJ01wegl5WT58aDtf\nhmw0HnOrgbWt4lRkxOra281hL74xcgtgMZQ32PTOy8wTEVTk03mmqlIq/dV4jgBc\nNh1FGQwGEeGlfbuNSB4nqgMN6zn1PmI7oCWLD9XLR6VZTebF7pGfpHtYczyivuxf\ne1YOro6e0mUqAiEAx4K3cPG3dxH91uU3L+sS2vzqXEVn2BmSMmkGczSOgn4=\n-----END DSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/dsa-public.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMIIGSDCCBDoGByqGSM44BAEwggQtAoICAQCvNs9u3/8FCmxiyehlHhH2deBy69xe\ngfxZmNGxvhk99UkZyEbsJ9EyUbQdHfi9xSl6E2PmkBq8SuF82eTUIRqXRPIOw6QF\nj/4kbbf3NeBHMxiNITqm1fmSPmka/S5dWijNI/8lluUjz9Kl3pNmRuUs0Bg6Xeyx\n9xQY3g0UNeXOaJa8/6rplSATy0PsJKvKJwgIqZdxVAhroAby6W1hrqYEBp7DMxuI\ni3ZNSj2yaCWkSoZ4egsK4tvd7vMt/QCFYNk6BNN97UoUSIrpNcx70dZh4/cw+7Iq\nFLbQaZP9ly7lU3jBuvRs/6ZNaTvTSgsnQ49DpiAaTKoGaH8GyL9OqeklZL+aNFsk\nR7cTY2Y0zCY/iPAnv1UkKWnkaD2RszqE+SYY2eFtsXOfeTBjemL38CKqkbKvcZQ+\nFe8/t9jAC78DkhIrDyvzuP8Qme3IjObnV9ybxDSarUgO3i02Qg7AkQhzjmH2vtkL\nVUAqTOUJrtdPTgaC4WgkxokFgRJhw4CZspGiOjw/9w3h8+56a6FAVCmWQUgzoW0b\n1wkyjZrKnq6Qf1Sny2fyPtiAT+b0Ev1KdQhs2W2L2PRw2B4pWfbhYLfyHD0PwzT+\nxHmBjJyVaH86i0K22hAjzJJnNK8HgYBFkdt7FqC+DUR1X3dy1jIBYYuSklgDO6Jd\nu3sVrIbt7aJ9iQIhAOkiV2wAUZVqIlFB2IqxZ1F45KPMfqHxzDoKjc4IhKI5AoIC\nAQCdJTb1TrmMrdbYGIB8pOVMHHbINQIMV6qeVrlqtnaeMaxQqI/aehwCsA8tCCDC\nT2t+q5/JtCW0zz7OOYTN5viZQJWFJtMfsG8/3TdTRgRptkkIcvHzSdPLCrZGBCzR\nCafje+zZTkSJ1hHTGPwII0AfmB3N338IvVFgAIcB/vOPifrxlo2QDL0nPUmNheM/\nogDEmHVb9jS+x0V0gn92e7GzIwJQJLAO9I0ClJ8BM7+3D4MJWkaAqjioTxvyWx9c\np6KG4zPJe5J78P3xg3ZQVZFNDqAXEaue2Dcs6fjVFdKRfHOLGCXuq5pwgnObyOsW\nQMlLHgBnyuC3/0ltOEBcX09WUJW/sYvU3O1SzhwMr7OwmV3g7WuUjdA7PkNar2gD\n4ePUw3cv0hbci/Y59+gBq5tcmG6/TE9Zia0KjTqY+BLCRY+MOcYJunW+4jzM9Ox/\nKGxqG4p5bSHwm21bgYHoJO0LUBVYDWkm6DmkGjfpLkbbiKFGx0bdDn9pOWeR7u3s\nfVOSHYq69X2EPlrle3Bye6IRwqPJHQVZHzVF2wAqH7tA0jcvHvlz3mLbYC6miflH\n9CRvTlXMd13b31tvvxzHmZbwOyDi0osXuSkMBxabHsmmQ8dD7lX03vrqx9n7P8+J\nVZ80AryDMlGf9x4tBwoLq46FxmA3SjhRiuZgTL2JzEnjjAOCAgYAAoICAQCLvsmo\nMlTEvguTqjqa5rbXof/jMmmCPkN6D1xUfHhyyX7bAVnr9ZEX43tX3cc88f5OEkDE\nW8cWzLRle+CjcEVMxFjpKMgBzwAI4TIqNZsZJz8AMUY1gzkhNHaxiT8hqSPWX6TF\nLb3pEDuzAhqmuObz5XWNdEcGQlTeugCKcUhdDBtThJoA/p6BzCO5qHJcP58PmVD2\niBcbz7LZQ+BLDw5HRNCOsd5N21F5VgGACRUenzX/Piot8Z4y41vXWt3FP6dh+/i6\nxQz/pD1Biaaq+GxutOhlHFdwpXc56KpYGrnVoHEAkMdDT84u5OTuz16+wt1FNHIP\nufhpL4iM6IGoqMYnb73IZxvlFNMuZ1bo4uhuvY+bFIZXBV7Xt9TbXtlVG+j/LpqP\npmw09FJGWWc6DrAqcPnCfDhzlXphSIVaYTR6kLdtE6ullUQcfqePmDVok4b5i7Zi\n4dEIIXZ1KyWccl8e/6fCuUhPf/qlNdbeXVL2Evud1NYCdpICBTuGbeoGqDsnsU7e\nX+Bmp4fSHCdNcHoJeVk+fGg7X4ZsNB5zq4G1reJUZMTq2tvNYS++MXILYDGUN9j0\nzsvMExFU5NN5pqpSKv3VeI4AXDYdRRkMBhHhpX27jUgeJ6oDDes59T5iO6Aliw/V\ny0elWU3mxe6Rn6R7WHM8or7sX3tWDq6OntJlKg==\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "test/ecdsa-private.pem",
    "content": "-----BEGIN EC PARAMETERS-----\nMIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////\n/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6\nk+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+\nkARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK\nfA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz\nucrC/GMlUQIBAQ==\n-----END EC PARAMETERS-----\n-----BEGIN EC PRIVATE KEY-----\nMIIBaAIBAQQgeg2m9tJJsnURyjTUihohiJahj9ETy3csUIt4EYrV+J2ggfowgfcC\nAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////\nMFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr\nvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE\naxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W\nK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8\nYyVRAgEBoUQDQgAEEWluurrkZECnq27UpNauq16f9+5DDMFJZ3HV43Ujc3tcXQ++\nN1T/0CAA8ve286f32s7rkqX/pPokI/HBpP5p3g==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "test/ecdsa-public-invalid.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\nAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\nNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\nRdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABEfZiYJDbghTGQ+KGnHGSl6K\nyUqK/BL2uJIg7Z0bx48v6+L7Ve8MCS17eptkMT2e4l5B/ZGDVUHb6uZ5xFROLBw=\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "test/ecdsa-public-x509.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDGjCCAsKgAwIBAgIJANuPNBWwp6wzMAkGByqGSM49BAEwRTELMAkGA1UEBhMC\nQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp\ndHMgUHR5IEx0ZDAeFw0xNzA2MTAxMTAzMjJaFw0yNzA2MDgxMTAzMjJaMEUxCzAJ\nBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l\ndCBXaWRnaXRzIFB0eSBMdGQwggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjO\nPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAA\nAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQaw\nzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i8\n5uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2\nQGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAE\nEWluurrkZECnq27UpNauq16f9+5DDMFJZ3HV43Ujc3tcXQ++N1T/0CAA8ve286f3\n2s7rkqX/pPokI/HBpP5p3qOBpzCBpDAdBgNVHQ4EFgQUAF43lnAvCztZZGaGMoxs\ncp6tpz8wdQYDVR0jBG4wbIAUAF43lnAvCztZZGaGMoxscp6tpz+hSaRHMEUxCzAJ\nBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l\ndCBXaWRnaXRzIFB0eSBMdGSCCQDbjzQVsKesMzAMBgNVHRMEBTADAQH/MAkGByqG\nSM49BAEDRwAwRAIgV039oh2RtcSwywQ/0dWAwc20NHxrgmKoQ5A3AS5A9d0CIBCV\n2AlKDFjmDC7zjldNhWbMcIlSSj71ghhhxeS0F8v1\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/ecdsa-public.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\nAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\nNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\nRdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABBFpbrq65GRAp6tu1KTWrqte\nn/fuQwzBSWdx1eN1I3N7XF0PvjdU/9AgAPL3tvOn99rO65Kl/6T6JCPxwaT+ad4=\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "test/encoding.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar atob = require('atob');\n\ndescribe('encoding', function() {\n\n  function b64_to_utf8 (str) {\n    return decodeURIComponent(escape(atob( str )));\n  }\n\n  it('should properly encode the token (utf8)', function () {\n    var expected = 'José';\n    var token = jwt.sign({ name: expected }, 'shhhhh');\n    var decoded_name = JSON.parse(b64_to_utf8(token.split('.')[1])).name;\n    expect(decoded_name).to.equal(expected);\n  });\n\n  it('should properly encode the token (binary)', function () {\n    var expected = 'José';\n    var token = jwt.sign({ name: expected }, 'shhhhh', { encoding: 'binary' });\n    var decoded_name = JSON.parse(atob(token.split('.')[1])).name;\n    expect(decoded_name).to.equal(expected);\n  });\n\n  it('should return the same result when decoding', function () {\n    var username = '測試';\n\n    var token = jwt.sign({\n      username: username\n    }, 'test');\n\n    var payload = jwt.verify(token, 'test');\n\n    expect(payload.username).to.equal(username);\n  });\n\n});\n"
  },
  {
    "path": "test/expires_format.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('expires option', function() {\n\n  it('should throw on deprecated expiresInSeconds option', function () {\n    expect(function () {\n      jwt.sign({foo: 123}, '123', { expiresInSeconds: 5 });\n    }).to.throw('\"expiresInSeconds\" is not allowed');\n  });\n\n});\n"
  },
  {
    "path": "test/header-kid.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils');\n\nfunction signWithKeyId(keyid, payload, callback) {\n  const options = {algorithm: 'HS256'};\n  if (keyid !== undefined) {\n    options.keyid = keyid;\n  }\n  testUtils.signJWTHelper(payload, 'secret', options, callback);\n}\n\ndescribe('keyid', function() {\n  describe('`jwt.sign` \"keyid\" option validation', function () {\n    [\n      true,\n      false,\n      null,\n      -1,\n      0,\n      1,\n      -1.1,\n      1.1,\n      -Infinity,\n      Infinity,\n      NaN,\n      [],\n      ['foo'],\n      {},\n      {foo: 'bar'},\n    ].forEach((keyid) => {\n      it(`should error with with value ${util.inspect(keyid)}`, function (done) {\n        signWithKeyId(keyid, {}, (err) => {\n          testUtils.asyncCheck(done, () => {\n            expect(err).to.be.instanceOf(Error);\n            expect(err).to.have.property('message', '\"keyid\" must be a string');\n          });\n        });\n      });\n    });\n\n    // undefined needs special treatment because {} is not the same as {keyid: undefined}\n    it('should error with with value undefined', function (done) {\n      testUtils.signJWTHelper({}, 'secret', {keyid: undefined, algorithm: 'HS256'}, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(Error);\n          expect(err).to.have.property('message', '\"keyid\" must be a string');\n        });\n      });\n    });\n  });\n\n  describe('when signing a token', function () {\n    it('should not add \"kid\" header when \"keyid\" option not provided', function(done) {\n      signWithKeyId(undefined, {}, (err, token) => {\n        testUtils.asyncCheck(done, () => {\n          const decoded = jwt.decode(token, {complete: true});\n          expect(err).to.be.null;\n          expect(decoded.header).to.not.have.property('kid');\n        });\n      });\n    });\n\n    it('should add \"kid\" header when \"keyid\" option is provided and an object payload', function(done) {\n      signWithKeyId('foo', {}, (err, token) => {\n        testUtils.asyncCheck(done, () => {\n          const decoded = jwt.decode(token, {complete: true});\n          expect(err).to.be.null;\n          expect(decoded.header).to.have.property('kid', 'foo');\n        });\n      });\n    });\n\n    it('should add \"kid\" header when \"keyid\" option is provided and a Buffer payload', function(done) {\n      signWithKeyId('foo', new Buffer('a Buffer payload'), (err, token) => {\n        testUtils.asyncCheck(done, () => {\n          const decoded = jwt.decode(token, {complete: true});\n          expect(err).to.be.null;\n          expect(decoded.header).to.have.property('kid', 'foo');\n        });\n      });\n    });\n\n    it('should add \"kid\" header when \"keyid\" option is provided and a string payload', function(done) {\n      signWithKeyId('foo', 'a string payload', (err, token) => {\n        testUtils.asyncCheck(done, () => {\n          const decoded = jwt.decode(token, {complete: true});\n          expect(err).to.be.null;\n          expect(decoded.header).to.have.property('kid', 'foo');\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/invalid_exp.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('invalid expiration', function() {\n\n  it('should fail with string', function (done) {\n    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjMiLCJmb28iOiJhZGFzIn0.cDa81le-pnwJMcJi3o3PBwB7cTJMiXCkizIhxbXAKRg';\n\n    jwt.verify(broken_token, '123', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n\n  });\n\n  it('should fail with 0', function (done) {\n    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjAsImZvbyI6ImFkYXMifQ.UKxix5T79WwfqAA0fLZr6UrhU-jMES2unwCOFa4grEA';\n\n    jwt.verify(broken_token, '123', function (err) {\n      expect(err.name).to.equal('TokenExpiredError');\n      done();\n    });\n\n  });\n\n  it('should fail with false', function (done) {\n    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOmZhbHNlLCJmb28iOiJhZGFzIn0.iBn33Plwhp-ZFXqppCd8YtED77dwWU0h68QS_nEQL8I';\n\n    jwt.verify(broken_token, '123', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n\n  });\n\n  it('should fail with true', function (done) {\n    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnRydWUsImZvbyI6ImFkYXMifQ.eOWfZCTM5CNYHAKSdFzzk2tDkPQmRT17yqllO-ItIMM';\n\n    jwt.verify(broken_token, '123', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n\n  });\n\n  it('should fail with object', function (done) {\n    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnt9LCJmb28iOiJhZGFzIn0.1JjCTsWLJ2DF-CfESjLdLfKutUt3Ji9cC7ESlcoBHSY';\n\n    jwt.verify(broken_token, '123', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n\n  });\n\n\n});"
  },
  {
    "path": "test/invalid_pub.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIJAMyz3mSPlaW4MA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV\nBAMUCyouYXV0aDAuY29tMB4XDTEzMDQxODE3MDE1MFoXDTI2MTIyNjE3MDE1MFow\nFjEUMBIGA1UEAxQLKi5hdXRoMC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQDZq1Ua0/BGm+TaBFoftKWeYMWrQG9Fx3g7ikErxljmyOvlwqkiat3q\nixX+Dxw9TFb5gbBjNJ+L3nt4YefJgLsYvsHqkOUxWsB+HM/ulJRVnVrZm1tI3Nbg\nxO1BQ7DrGfBpq2KCxtQCaQFRlQJw1+qS5LwrdIvihB7Kc142VElCFFHJ6+09eMUy\njy00Z5pfQr4Am6W6eEOS9ObDbNs4XgKOcWe5khWXj3UStou+VgbAg40XcYht2IbY\ngMfKF+VUZOy3+e+aRTqPOBU3MAeb0tvCCPUQJbNAUHgSKVhAvNf8mRwttVsOLT70\nanjjeCOd7RKS8fVKBwc2KtgNkghYdPY9AgMBAAGjdzB1MB0GA1UdDgQWBBSi4+X0\n+MvCKDdd375mDhx/ZBbJ4DBGBgNVHSMEPzA9gBSi4+X0+MvCKDdd375mDhx/ZBbJ\n4KEapBgwFjEUMBIGA1UEAxQLKi5hdXRoMC5jb22CCQDMs95kj5WluDAMBgNVHRME\nBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBi0qPe0DzlPSufq+Gdk2Fwf1pGEtjA\nD34IxxJ9SX6r1DS/NIP7IOLUnNU8cP8BQWl7i413v29jJsNV457pjdmqf8J7OE9O\neF5Yz1x91gY/27561Iga/TQeIVOlFQAgx66eLfUFFoAig3hz2srZo5TzYBixMJsS\nfYMXHPiU7KoLUqYXvpSXIllstQCu51KCC6t9H7wZ92lTES1v76hFY4edQ30sftPo\nkjAYWGEhMjPo/r4THcdSMqKXoRtCGEun4pTXid7MJcTgdGDrAJddLWi6SxKecEVB\nMhMu4XfUCdxCwqQPjHeJ+zE49A1CUdBB2FN3BNLbmTTwEBgmuwyGRzhj\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/issue_147.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('issue 147 - signing with a sealed payload', function() {\n\n  it('should put the expiration claim', function () {\n    var token = jwt.sign(Object.seal({foo: 123}), '123', { expiresIn: 10 });\n    var result = jwt.verify(token, '123');\n    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + 10, 0.2);\n  });\n\n});"
  },
  {
    "path": "test/issue_304.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('issue 304 - verifying values other than strings', function() {\n\n  it('should fail with numbers', function (done) {\n    jwt.verify(123, 'foo', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n  });\n\n  it('should fail with objects', function (done) {\n    jwt.verify({ foo: 'bar' }, 'biz', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n  });\n\n  it('should fail with arrays', function (done) {\n    jwt.verify(['foo'], 'bar', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n  });\n\n  it('should fail with functions', function (done) {\n    jwt.verify(function() {}, 'foo', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n  });\n\n  it('should fail with booleans', function (done) {\n    jwt.verify(true, 'foo', function (err) {\n      expect(err.name).to.equal('JsonWebTokenError');\n      done();\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/issue_70.tests.js",
    "content": "var jwt = require('../');\n\ndescribe('issue 70 - public key start with BEING PUBLIC KEY', function () {\n\n  it('should work', function (done) {\n    var fs = require('fs');\n    var cert_pub = fs.readFileSync(__dirname + '/rsa-public.pem');\n    var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');\n\n    var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});\n\n    jwt.verify(token, cert_pub, done);\n  });\n\n});"
  },
  {
    "path": "test/jwt.asymmetric_signing.tests.js",
    "content": "const jwt = require('../index');\nconst PS_SUPPORTED = require('../lib/psSupported');\nconst fs = require('fs');\nconst path = require('path');\n\nconst expect = require('chai').expect;\nconst assert = require('chai').assert;\nconst ms = require('ms');\n\nfunction loadKey(filename) {\n  return fs.readFileSync(path.join(__dirname, filename));\n}\n\nconst algorithms = {\n  RS256: {\n    pub_key: loadKey('pub.pem'),\n    priv_key: loadKey('priv.pem'),\n    invalid_pub_key: loadKey('invalid_pub.pem')\n  },\n  ES256: {\n    // openssl ecparam -name secp256r1 -genkey -param_enc explicit -out ecdsa-private.pem\n    priv_key: loadKey('ecdsa-private.pem'),\n    // openssl ec -in ecdsa-private.pem -pubout -out ecdsa-public.pem\n    pub_key: loadKey('ecdsa-public.pem'),\n    invalid_pub_key: loadKey('ecdsa-public-invalid.pem')\n  }\n};\n\nif (PS_SUPPORTED) {\n  algorithms.PS256 = {\n    pub_key: loadKey('pub.pem'),\n    priv_key: loadKey('priv.pem'),\n    invalid_pub_key: loadKey('invalid_pub.pem')\n  };\n}\n\n\ndescribe('Asymmetric Algorithms', function() {\n  Object.keys(algorithms).forEach(function (algorithm) {\n    describe(algorithm, function () {\n      const pub = algorithms[algorithm].pub_key;\n      const priv = algorithms[algorithm].priv_key;\n\n      // \"invalid\" means it is not the public key for the loaded \"priv\" key\n      const invalid_pub = algorithms[algorithm].invalid_pub_key;\n\n      describe('when signing a token', function () {\n        const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm });\n\n        it('should be syntactically valid', function () {\n          expect(token).to.be.a('string');\n          expect(token.split('.')).to.have.length(3);\n        });\n\n        context('asynchronous', function () {\n          it('should validate with public key', function (done) {\n            jwt.verify(token, pub, function (err, decoded) {\n              assert.ok(decoded.foo);\n              assert.equal('bar', decoded.foo);\n              done();\n            });\n          });\n\n          it('should throw with invalid public key', function (done) {\n            jwt.verify(token, invalid_pub, function (err, decoded) {\n              assert.isUndefined(decoded);\n              assert.isNotNull(err);\n              done();\n            });\n          });\n        });\n\n        context('synchronous', function () {\n          it('should validate with public key', function () {\n            const decoded = jwt.verify(token, pub);\n            assert.ok(decoded.foo);\n            assert.equal('bar', decoded.foo);\n          });\n\n          it('should throw with invalid public key', function () {\n            const jwtVerify = jwt.verify.bind(null, token, invalid_pub)\n            assert.throw(jwtVerify, 'invalid signature');\n          });\n        });\n\n      });\n\n      describe('when signing a token with expiration', function () {\n        it('should be valid expiration', function (done) {\n          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: '10m' });\n          jwt.verify(token, pub, function (err, decoded) {\n            assert.isNotNull(decoded);\n            assert.isNull(err);\n            done();\n          });\n        });\n\n        it('should be invalid', function (done) {\n          // expired token\n          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: -1 * ms('10m') });\n          jwt.verify(token, pub, function (err, decoded) {\n            assert.isUndefined(decoded);\n            assert.isNotNull(err);\n            assert.equal(err.name, 'TokenExpiredError');\n            assert.instanceOf(err.expiredAt, Date);\n            assert.instanceOf(err, jwt.TokenExpiredError);\n            done();\n          });\n        });\n\n        it('should NOT be invalid', function (done) {\n          // expired token\n          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: -1 * ms('10m') });\n\n          jwt.verify(token, pub, { ignoreExpiration: true }, function (err, decoded) {\n            assert.ok(decoded.foo);\n            assert.equal('bar', decoded.foo);\n            done();\n          });\n        });\n      });\n\n      describe('when verifying a malformed token', function () {\n        it('should throw', function (done) {\n          jwt.verify('fruit.fruit.fruit', pub, function (err, decoded) {\n            assert.isUndefined(decoded);\n            assert.isNotNull(err);\n            assert.equal(err.name, 'JsonWebTokenError');\n            done();\n          });\n        });\n      });\n\n      describe('when decoding a jwt token with additional parts', function () {\n        const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm });\n\n        it('should throw', function (done) {\n          jwt.verify(token + '.foo', pub, function (err, decoded) {\n            assert.isUndefined(decoded);\n            assert.isNotNull(err);\n            done();\n          });\n        });\n      });\n\n      describe('when decoding a invalid jwt token', function () {\n        it('should return null', function (done) {\n          const payload = jwt.decode('whatever.token');\n          assert.isNull(payload);\n          done();\n        });\n      });\n\n      describe('when decoding a valid jwt token', function () {\n        it('should return the payload', function (done) {\n          const obj = { foo: 'bar' };\n          const token = jwt.sign(obj, priv, { algorithm: algorithm });\n          const payload = jwt.decode(token);\n          assert.equal(payload.foo, obj.foo);\n          done();\n        });\n        it('should return the header and payload and signature if complete option is set', function (done) {\n          const obj = { foo: 'bar' };\n          const token = jwt.sign(obj, priv, { algorithm: algorithm });\n          const decoded = jwt.decode(token, { complete: true });\n          assert.equal(decoded.payload.foo, obj.foo);\n          assert.deepEqual(decoded.header, { typ: 'JWT', alg: algorithm });\n          assert.ok(typeof decoded.signature == 'string');\n          done();\n        });\n      });\n    });\n  });\n\n  describe('when signing a token with an unsupported private key type', function () {\n    it('should throw an error', function() {\n      const obj = { foo: 'bar' };\n      const key = loadKey('dsa-private.pem');\n      const algorithm = 'RS256';\n\n      expect(function() {\n        jwt.sign(obj, key, { algorithm });\n      }).to.throw('Unknown key type \"dsa\".');\n    });\n  });\n\n  describe('when signing a token with an incorrect private key type', function () {\n    it('should throw a validation error if key validation is enabled', function() {\n      const obj = { foo: 'bar' };\n      const key = loadKey('rsa-private.pem');\n      const algorithm = 'ES256';\n\n      expect(function() {\n        jwt.sign(obj, key, { algorithm });\n      }).to.throw(/\"alg\" parameter for \"rsa\" key type must be one of:/);\n    });\n\n    it('should throw an unknown error if key validation is disabled', function() {\n      const obj = { foo: 'bar' };\n      const key = loadKey('rsa-private.pem');\n      const algorithm = 'ES256';\n\n      expect(function() {\n        jwt.sign(obj, key, { algorithm, allowInvalidAsymmetricKeyTypes: true });\n      }).to.not.throw(/\"alg\" parameter for \"rsa\" key type must be one of:/);\n    });\n  });\n});\n"
  },
  {
    "path": "test/jwt.hs.tests.js",
    "content": "const jwt = require('../index');\n\nconst jws = require('jws');\nconst expect = require('chai').expect;\nconst assert = require('chai').assert;\nconst { generateKeyPairSync } = require('crypto')\n\ndescribe('HS256', function() {\n\n  describe(\"when signing using HS256\", function () {\n    it('should throw if the secret is an asymmetric key', function () {\n      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });\n\n      expect(function () {\n        jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'HS256' })\n      }).to.throw(Error, 'must be a symmetric key')\n    })\n\n    it('should throw if the payload is undefined', function () {\n      expect(function () {\n        jwt.sign(undefined, \"secret\", { algorithm: 'HS256' })\n      }).to.throw(Error, 'payload is required')\n    })\n\n    it('should throw if options is not a plain object', function () {\n      expect(function () {\n        jwt.sign({ foo: 'bar' }, \"secret\", ['HS256'])\n      }).to.throw(Error, 'Expected \"options\" to be a plain object')\n    })\n  })\n\n  describe('with a token signed using HS256', function() {\n    var secret = 'shhhhhh';\n\n    var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });\n\n    it('should be syntactically valid', function() {\n      expect(token).to.be.a('string');\n      expect(token.split('.')).to.have.length(3);\n    });\n\n    it('should be able to validate without options', function(done) {\n      var callback = function(err, decoded) {\n        assert.ok(decoded.foo);\n        assert.equal('bar', decoded.foo);\n        done();\n      };\n      callback.issuer = \"shouldn't affect\";\n      jwt.verify(token, secret, callback );\n    });\n\n    it('should validate with secret', function(done) {\n      jwt.verify(token, secret, function(err, decoded) {\n        assert.ok(decoded.foo);\n        assert.equal('bar', decoded.foo);\n        done();\n      });\n    });\n\n    it('should throw with invalid secret', function(done) {\n      jwt.verify(token, 'invalid secret', function(err, decoded) {\n        assert.isUndefined(decoded);\n        assert.isNotNull(err);\n        done();\n      });\n    });\n\n    it('should throw with secret and token not signed', function(done) {\n      const header = { alg: 'none' };\n      const payload = { foo: 'bar' };\n      const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });\n      jwt.verify(token, 'secret', function(err, decoded) {\n        assert.isUndefined(decoded);\n        assert.isNotNull(err);\n        done();\n      });\n    });\n\n    it('should throw with falsy secret and token not signed', function(done) {\n      const header = { alg: 'none' };\n      const payload = { foo: 'bar' };\n      const token = jws.sign({ header, payload, secret: null, encoding: 'utf8' });\n      jwt.verify(token, 'secret', function(err, decoded) {\n        assert.isUndefined(decoded);\n        assert.isNotNull(err);\n        done();\n      });\n    });\n\n    it('should throw when verifying null', function(done) {\n      jwt.verify(null, 'secret', function(err, decoded) {\n        assert.isUndefined(decoded);\n        assert.isNotNull(err);\n        done();\n      });\n    });\n\n    it('should return an error when the token is expired', function(done) {\n      var token = jwt.sign({ exp: 1 }, secret, { algorithm: 'HS256' });\n      jwt.verify(token, secret, { algorithm: 'HS256' }, function(err, decoded) {\n        assert.isUndefined(decoded);\n        assert.isNotNull(err);\n        done();\n      });\n    });\n\n    it('should NOT return an error when the token is expired with \"ignoreExpiration\"', function(done) {\n      var token = jwt.sign({ exp: 1, foo: 'bar' }, secret, { algorithm: 'HS256' });\n      jwt.verify(token, secret, { algorithm: 'HS256', ignoreExpiration: true }, function(err, decoded) {\n        assert.ok(decoded.foo);\n        assert.equal('bar', decoded.foo);\n        assert.isNull(err);\n        done();\n      });\n    });\n\n    it('should default to HS256 algorithm when no options are passed', function() {\n      var token = jwt.sign({ foo: 'bar' }, secret);\n      var verifiedToken = jwt.verify(token, secret);\n      assert.ok(verifiedToken.foo);\n      assert.equal('bar', verifiedToken.foo);\n    });\n  });\n\n  describe('should fail verification gracefully with trailing space in the jwt', function() {\n    var secret = 'shhhhhh';\n    var token  = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });\n\n    it('should return the \"invalid token\" error', function(done) {\n      var malformedToken = token + ' '; // corrupt the token by adding a space\n      jwt.verify(malformedToken, secret, { algorithm: 'HS256', ignoreExpiration: true }, function(err) {\n        assert.isNotNull(err);\n        assert.equal('JsonWebTokenError', err.name);\n        assert.equal('invalid token', err.message);\n        done();\n      });\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/jwt.malicious.tests.js",
    "content": "const jwt = require('../index');\nconst crypto = require(\"crypto\");\nconst {expect} = require('chai');\nconst JsonWebTokenError = require(\"../lib/JsonWebTokenError\");\n\ndescribe('when verifying a malicious token', function () {\n  // attacker has access to the public rsa key, but crafts the token as HS256\n  // with kid set to the id of the rsa key, instead of the id of the hmac secret.\n  // const maliciousToken = jwt.sign(\n  //   {foo: 'bar'},\n  //   pubRsaKey,\n  //   {algorithm: 'HS256', keyid: 'rsaKeyId'}\n  // );\n  // consumer accepts self signed tokens (HS256) and third party tokens (RS256)\n  const options = {algorithms: ['RS256', 'HS256']};\n\n  const {\n    publicKey: pubRsaKey\n  } = crypto.generateKeyPairSync('rsa', {modulusLength: 2048});\n\n  it('should not allow HMAC verification with an RSA key in KeyObject format', function () {\n    const maliciousToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJzYUtleUlkIn0.eyJmb28iOiJiYXIiLCJpYXQiOjE2NTk1MTA2MDh9.cOcHI1TXPbxTMlyVTfjArSWskrmezbrG8iR7uJHwtrQ';\n\n    expect(() => jwt.verify(maliciousToken, pubRsaKey, options)).to.throw(JsonWebTokenError, 'must be a symmetric key');\n  })\n\n  it('should not allow HMAC verification with an RSA key in PEM format', function () {\n    const maliciousToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJzYUtleUlkIn0.eyJmb28iOiJiYXIiLCJpYXQiOjE2NTk1MTA2MDh9.cOcHI1TXPbxTMlyVTfjArSWskrmezbrG8iR7uJHwtrQ';\n\n    expect(() => jwt.verify(maliciousToken, pubRsaKey.export({type: 'spki', format: 'pem'}), options)).to.throw(JsonWebTokenError, 'must be a symmetric key');\n  })\n\n  it('should not allow arbitrary execution from malicious Buffers containing objects with overridden toString functions', function () {\n    const token = jwt.sign({\"foo\": \"bar\"}, 'secret')\n    const maliciousBuffer = {toString: () => {throw new Error(\"Arbitrary Code Execution\")}}\n\n    expect(() => jwt.verify(token, maliciousBuffer)).to.throw(Error, 'not valid key material');\n  })\n})\n"
  },
  {
    "path": "test/noTimestamp.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('noTimestamp', function() {\n\n  it('should work with string', function () {\n    var token = jwt.sign({foo: 123}, '123', { expiresIn: '5m' , noTimestamp: true });\n    var result = jwt.verify(token, '123');\n    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + (5*60), 0.5);\n  });\n\n});\n"
  },
  {
    "path": "test/non_object_values.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('non_object_values values', function() {\n\n  it('should work with string', function () {\n    var token = jwt.sign('hello', '123');\n    var result = jwt.verify(token, '123');\n    expect(result).to.equal('hello');\n  });\n\n  it('should work with number', function () {\n    var token = jwt.sign(123, '123');\n    var result = jwt.verify(token, '123');\n    expect(result).to.equal('123');\n  });\n\n});\n"
  },
  {
    "path": "test/option-complete.test.js",
    "content": "'use strict';\n\nconst jws = require('jws');\nconst expect = require('chai').expect;\nconst path = require('path');\nconst fs = require('fs');\nconst testUtils = require('./test-utils')\n\ndescribe('complete option', function () {\n  const secret = fs.readFileSync(path.join(__dirname, 'priv.pem'));\n  const pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));\n\n  const header = { alg: 'RS256' };\n  const payload = { iat: Math.floor(Date.now() / 1000 ) };\n  const signed = jws.sign({ header, payload, secret, encoding: 'utf8' });\n  const signature = jws.decode(signed).signature;\n\n  [\n    {\n      description: 'should return header, payload and signature',\n      complete: true,\n    },\n  ].forEach((testCase) => {\n    it(testCase.description, function (done) {\n      testUtils.verifyJWTHelper(signed, pub, { typ: 'JWT', complete: testCase.complete }, (err, decoded) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded.header).to.have.property('alg', header.alg);\n          expect(decoded.payload).to.have.property('iat', payload.iat);\n          expect(decoded).to.have.property('signature', signature);\n        });\n      });\n    });\n  });\n  [\n    {\n      description: 'should return payload',\n      complete: false,\n    },\n  ].forEach((testCase) => {\n    it(testCase.description, function (done) {\n      testUtils.verifyJWTHelper(signed, pub, { typ: 'JWT', complete: testCase.complete }, (err, decoded) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded.header).to.be.undefined;\n          expect(decoded.payload).to.be.undefined;\n          expect(decoded.signature).to.be.undefined;\n          expect(decoded).to.have.property('iat', payload.iat);\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/option-maxAge.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst util = require('util');\n\ndescribe('maxAge option', function() {\n  let token;\n\n  let fakeClock;\n  beforeEach(function() {\n    fakeClock = sinon.useFakeTimers({now: 60000});\n    token = jwt.sign({iat: 70}, 'secret', {algorithm: 'HS256'});\n  });\n\n  afterEach(function() {\n    fakeClock.uninstall();\n  });\n\n  [\n    {\n      description: 'should work with a positive string value',\n      maxAge: '3s',\n    },\n    {\n      description: 'should work with a negative string value',\n      maxAge: '-3s',\n    },\n    {\n      description: 'should work with a positive numeric value',\n      maxAge: 3,\n    },\n    {\n      description: 'should work with a negative numeric value',\n      maxAge: -3,\n    },\n  ].forEach((testCase) => {\n    it(testCase.description, function (done) {\n      expect(jwt.verify(token, 'secret', {maxAge: '3s', algorithm: 'HS256'})).to.not.throw;\n      jwt.verify(token, 'secret', {maxAge: testCase.maxAge, algorithm: 'HS256'}, (err) => {\n        expect(err).to.be.null;\n        done();\n      })\n    });\n  });\n\n  [\n    true,\n    'invalid',\n    [],\n    ['foo'],\n    {},\n    {foo: 'bar'},\n  ].forEach((maxAge) => {\n    it(`should error with value ${util.inspect(maxAge)}`, function (done) {\n      expect(() => jwt.verify(token, 'secret', {maxAge, algorithm: 'HS256'})).to.throw(\n        jwt.JsonWebTokenError,\n        '\"maxAge\" should be a number of seconds or string representing a timespan eg: \"1d\", \"20h\", 60'\n      );\n      jwt.verify(token, 'secret', {maxAge, algorithm: 'HS256'}, (err) => {\n        expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n        expect(err.message).to.equal(\n          '\"maxAge\" should be a number of seconds or string representing a timespan eg: \"1d\", \"20h\", 60'\n        );\n        done();\n      })\n    });\n  });\n});\n"
  },
  {
    "path": "test/option-nonce.test.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-utils')\n\ndescribe('nonce option', function () {\n  let token;\n\n  beforeEach(function () {\n    token = jwt.sign({ nonce: 'abcde' }, 'secret', { algorithm: 'HS256' });\n  });\n  [\n    {\n      description: 'should work with a string',\n      nonce: 'abcde',\n    },\n  ].forEach((testCase) => {\n    it(testCase.description, function (done) {\n      testUtils.verifyJWTHelper(token, 'secret', { nonce: testCase.nonce }, (err, decoded) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.null;\n          expect(decoded).to.have.property('nonce', 'abcde');\n        });\n      });\n    });\n  });\n  [\n    true,\n    false,\n    null,\n    -1,\n    0,\n    1,\n    -1.1,\n    1.1,\n    -Infinity,\n    Infinity,\n    NaN,\n    '',\n    ' ',\n    [],\n    ['foo'],\n    {},\n    { foo: 'bar' },\n  ].forEach((nonce) => {\n    it(`should error with value ${util.inspect(nonce)}`, function (done) {\n      testUtils.verifyJWTHelper(token, 'secret', { nonce }, (err) => {\n        testUtils.asyncCheck(done, () => {\n          expect(err).to.be.instanceOf(jwt.JsonWebTokenError);\n          expect(err).to.have.property('message', 'nonce must be a non-empty string')\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/prime256v1-private.pem",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMP1Xt/ic2jAHJva2Pll866d1jYL+dk3VdLytEU1+LFmoAoGCCqGSM49\nAwEHoUQDQgAEvIywoA1H1a2XpPPTqsRxSk6YnNRVsu4E+wTvb7uV6Yttvko9zWar\njmtM3LHDXk/nHn+Pva0KD+lby8gb2daHGg==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "test/priv.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvtH4wKLYlIXZlfYQFJtXZVC3fD8XMarzwvb/fHUyJ6NvNStN\n+H7GHp3/QhZbSaRyqK5hu5xXtFLgnI0QG8oE1NlXbczjH45LeHWhPIdc2uHSpzXi\nc78kOugMY1vng4J10PF6+T2FNaiv0iXeIQq9xbwwPYpflViQyJnzGCIZ7VGan6Gb\nRKzyTKcB58yx24pJq+CviLXEY52TIW1l5imcjGvLtlCp1za9qBZa4XGoVqHi1kRX\nkdDSHty6lZWj3KxoRvTbiaBCH+75U7rifS6fR9lqjWE57bCGoz7+BBu9YmPKtI1K\nkyHFqWpxaJc/AKf9xgg+UumeqVcirUmAsHJrMwIDAQABAoIBAQCYKw05YSNhXVPk\neHLeW/pXuwR3OkCexPrakOmwMC0s2vIF7mChN0d6hvhVlUp68X7V8SnS2JxAGo8v\niHY+Et3DdwZ3cxnzwh+BEhzgDfoIOmkoGppZPyX/K6klWtbGUrTtSISOWXbvEXQU\nG0qGAvDOzIGTsdMDX7slnU70Ac23JybPY5qBSiE+ky8U4dm2fUHMroWub4QP5vA/\nnqyWqX2FB/MEAbcujaknDQrFCtbmtUYlBbJCKGd9V3cGEqp6H7oH+ah2ofMc91gJ\nmCHk3YyWZB/bcVXH3CA+s1ywvCOVDBZ3Nw7Pt9zIcv6Rl9UKIy+Nx0QjXxR90Hla\nTr0GHIShAoGBAPsD7uXm+0ksnGyKRYgvlVad8Z8FUFT6bf4B+vboDbx40FO8O/5V\nPraBPC5z8YRSBOQ/WfccPQzakkA28F2pXlRpXu5JcErVWnyyUiKpX5sw6iPenQR2\nJO9hY/GFbKiwUhVHpvWMcXFqFLSQu2A86jPnFFEfG48ZT4IhTzINKJVZAoGBAMKc\nB3YGfVfY9qiRFXzYRdSRLg5c8p/HzuWwXc9vfJ4kQTDkPXe/+nqD67rzeT54uVec\njKoIrsCu4BfEaoyvOT+1KmUfdEpBgYZuuEC4CZf7dgKbXOpPVvZDMyJ/e7HyqTpw\nmvIYJLPm2fNAcAsnbrNX5mhLwwzEIltbplUUeRdrAoGBAKhZgPYsLkhrZRXevreR\nwkTvdUfD1pbHxtFfHqROCjhnhsFCM7JmFcNtdaFqHYczQxiZ7IqxI7jlNsVek2Md\n3qgaa5LBKlDmOuP67N9WXUrGSaJ5ATIm0qrB1Lf9VlzktIiVH8L7yHHaRby8fQ8U\ni7b3ukaV6HPW895A3M6iyJ8xAoGAInp4S+3MaTL0SFsj/nFmtcle6oaHKc3BlyoP\nBMBQyMfNkPbu+PdXTjtvGTknouzKkX4X4cwWAec5ppxS8EffEa1sLGxNMxa19vZI\nyJaShI21k7Ko3I5f7tNrDNKfPKCsYMEwgnHKluDwfktNTnyW/Uk2dgXuMaXSHHN5\nXZt59K8CgYArGVOWK7LUmf3dkTIs3tXBm4/IMtUZmWmcP9C8Xe/Dg/IdQhK5CIx4\nVXl8rgZNeX/5/4nJ8Q3LrdLau1Iz620trNRGU6sGMs3x4WQbSq93RRbFzfG1oK74\nIOo5yIBxImQOSk5jz31gF9RJb15SDBIxonuWv8qAERyUfvrmEwR0kg==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/pub.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMKR/NsyfcazMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTIxMTEyMjM0MzQxWhcNMTYxMjIxMjM0MzQxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAvtH4wKLYlIXZlfYQFJtXZVC3fD8XMarzwvb/fHUyJ6NvNStN+H7GHp3/\nQhZbSaRyqK5hu5xXtFLgnI0QG8oE1NlXbczjH45LeHWhPIdc2uHSpzXic78kOugM\nY1vng4J10PF6+T2FNaiv0iXeIQq9xbwwPYpflViQyJnzGCIZ7VGan6GbRKzyTKcB\n58yx24pJq+CviLXEY52TIW1l5imcjGvLtlCp1za9qBZa4XGoVqHi1kRXkdDSHty6\nlZWj3KxoRvTbiaBCH+75U7rifS6fR9lqjWE57bCGoz7+BBu9YmPKtI1KkyHFqWpx\naJc/AKf9xgg+UumeqVcirUmAsHJrMwIDAQABo4GnMIGkMB0GA1UdDgQWBBTs83nk\nLtoXFlmBUts3EIxcVvkvcjB1BgNVHSMEbjBsgBTs83nkLtoXFlmBUts3EIxcVvkv\ncqFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMKR/NsyfcazMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABw7w/5k4d5dVDgd/OOOmXdaaCIKvt7d\n3ntlv1SSvAoKT8d8lt97Dm5RrmefBI13I2yivZg5bfTge4+vAV6VdLFdWeFp1b/F\nOZkYUv6A8o5HW0OWQYVX26zIqBcG2Qrm3reiSl5BLvpj1WSpCsYvs5kaO4vFpMak\n/ICgdZD+rxwxf8Vb/6fntKywWSLgwKH3mJ+Z0kRlpq1g1oieiOm1/gpZ35s0Yuor\nXZba9ptfLCYSggg/qc3d3d0tbHplKYkwFm7f5ORGHDSD5SJm+gI7RPE+4bO8q79R\nPAfbG1UGuJ0b/oigagciHhJp851SQRYf3JuNSc17BnK2L5IEtzjqr+Q=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/rsa-private.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ\n7rBasuLI8AcfX5/10scSfQNCsTLV2tMKQaHuvyrVfwY0dINk+nkqB74QcT2oCCH9\nXduJjDuwWA4xLqAKuF96FsIes52opEM50W7/W7DZCKXkC8fFPFj6QF5ZzApDw2Qs\nu3yMRmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN40vXv9c4xiSafVvnx9BwYL7H1Q8N\niK9LGEN6+JSWfgckQCs6UUBOXSZdreNN9zbQCwyzee7bOJqXUDAuLcFARzPw1EsZ\nAyjVtGCKIQ0/btqK+jFunT2NBC8RItanDZpptQIDAQABAoIBAQCsssO4Pra8hFMC\ngX7tr0x+tAYy1ewmpW8stiDFilYT33YPLKJ9HjHbSms0MwqHftwwTm8JDc/GXmW6\nqUui+I64gQOtIzpuW1fvyUtHEMSisI83QRMkF6fCSQm6jJ6oQAtOdZO6R/gYOPNb\n3gayeS8PbMilQcSRSwp6tNTVGyC33p43uUUKAKHnpvAwUSc61aVOtw2wkD062XzM\nhJjYpHm65i4V31AzXo8HF42NrAtZ8K/AuQZne5F/6F4QFVlMKzUoHkSUnTp60XZx\nX77GuyDeDmCgSc2J7xvR5o6VpjsHMo3ek0gJk5ZBnTgkHvnpbULCRxTmDfjeVPue\nv3NN2TBFAoGBAPxbqNEsXPOckGTvG3tUOAAkrK1hfW3TwvrW/7YXg1/6aNV4sklc\nvqn/40kCK0v9xJIv9FM/l0Nq+CMWcrb4sjLeGwHAa8ASfk6hKHbeiTFamA6FBkvQ\n//7GP5khD+y62RlWi9PmwJY21lEkn2mP99THxqvZjQiAVNiqlYdwiIc7AoGBAMH8\nf2Ay7Egc2KYRYU2qwa5E/Cljn/9sdvUnWM+gOzUXpc5sBi+/SUUQT8y/rY4AUVW6\nYaK7chG9YokZQq7ZwTCsYxTfxHK2pnG/tXjOxLFQKBwppQfJcFSRLbw0lMbQoZBk\nS+zb0ufZzxc2fJfXE+XeJxmKs0TS9ltQuJiSqCPPAoGBALEc84K7DBG+FGmCl1sb\nZKJVGwwknA90zCeYtadrIT0/VkxchWSPvxE5Ep+u8gxHcqrXFTdILjWW4chefOyF\n5ytkTrgQAI+xawxsdyXWUZtd5dJq8lxLtx9srD4gwjh3et8ZqtFx5kCHBCu29Fr2\nPA4OmBUMfrs0tlfKgV+pT2j5AoGBAKnA0Z5XMZlxVM0OTH3wvYhI6fk2Kx8TxY2G\nnxsh9m3hgcD/mvJRjEaZnZto6PFoqcRBU4taSNnpRr7+kfH8sCht0k7D+l8AIutL\nffx3xHv9zvvGHZqQ1nHKkaEuyjqo+5kli6N8QjWNzsFbdvBQ0CLJoqGhVHsXuWnz\nW3Z4cBbVAoGAEtnwY1OJM7+R2u1CW0tTjqDlYU2hUNa9t1AbhyGdI2arYp+p+umA\nb5VoYLNsdvZhqjVFTrYNEuhTJFYCF7jAiZLYvYm0C99BqcJnJPl7JjWynoNHNKw3\n9f6PIOE1rAmPE8Cfz/GFF5115ZKVlq+2BY8EKNxbCIy2d/vMEvisnXI=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/rsa-pss-invalid-salt-length-private.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIE8gIBADBCBgkqhkiG9w0BAQowNaAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI\nhvcNAQEIMA0GCWCGSAFlAwQCAQUAogQCAgQABIIEpzCCBKMCAQACggEBAJy3FuDR\n1qKXsC8o+0xDJbuJCnysT71EFDGQY2/b3cZmxW3rzDYLyE65t2Go1jeK5Kxs+kwS\n1VxfefD8DifeDZN66wjRse4iWLcxmQB5FfishXOdozciimgXNvXJNS8X//feSofl\nvDQaTUI0NJnw1qQ2CB0pgGInwajsRKpWnDOhfk3NA/cmGlmfhTtDSTxq0ReytUie\nTjY7gy+S9YYm4bAgBcMeoup0GEPzYccK4+1yCmWzQZGFcrY1cuB9bL+vT7ajQFhe\nWVKlp6z35GyBF2zI7gJSkHpUHaWV5+Z9aTr6+YP6U7xuCRvXQ/l6BEOUjt4Es2YG\n3frgxeVbOs1gAakCAwEAAQKCAQAMvFxhnOwCfq1Ux9HUWsigOvzdMOuyB+xUMtXB\n625Uh1mYG0eXRNHcg/9BMoVmMiVvVdPphsZMIX45dWJ5HvSffafIKbJ6FdR73s3+\nWdjNQsf9o1v2SRpSZ0CSLO3ji+HDdQ89iBAJc/G/ZZq4v/fRlIqIRC0ozO5SGhFi\nfnNnRqH78d2KeJMX/g9jBZM8rJQCi+pb0keHmFmLJ5gZa4HokE8rWQJQY46PVYUH\nW2BwEJToMl3MPC7D95soWVuFt3KHnIWhuma/tnCmd2AUvcMrdWq0CwStH3vuX4LB\nvJug0toWkobt1tzZgzzCASb2EpzJj8UNxP1CzTQWsvl8OephAoGBAMVnmZeLHoh2\nkxn/+rXetZ4Msjgu19MHNQAtlMvqzwZLan0K/BhnHprJLy4SDOuQYIs+PYJuXdT7\nYv2mp9kwTPz8glP9LAto4MDeDfCu0cyXmZb2VQcT/lqVyrwfx3Psqxm/Yxg62YKr\naQE8WqgZGUdOvU9dYU+7EmPlYpdGpPVlAoGBAMs7ks+12oE6kci3WApdnt0kk5+f\n8fbQ0lp2vR3tEw8DURa5FnHWA4o46XvcMcuXwZBrpxANPNAxJJjMBs1hSkc8h4hd\n4vjtRNYJpj+uBdDIRmdqTzbpWv+hv8Xpiol5EVgnMVs2UZWDjoxQ+mYa1R8tAUfj\nojzV2KBMWGCoHgj1AoGALki6JGQEBq72kpQILnhHUQVdC/s/s0TvUlldl+o4HBu2\nnhbjQL182YHuQ/kLenfhiwRO27QQ4A0JCrv2gt/mTTLPQ+4KU6qFd/MYhaQXoMay\nxkh/aydu7cJNRIqW80E8ZM8Q5u91bEPQXO/PubYYzTVTAba9SDpud2mjEiEIMFkC\ngYEAxINEQEgtkkuZ76UpIkzIcjkN7YlxJCFjZUnvL+KvTRL986TgyQ4RujOxwKx4\nEc8ZwZX2opTKOt1p771IzorGkf87ZmayM9TpfLUz5dtVkD43pYOsOQKHlStIDgz2\ngltoo/6xwOrTFGlzCsa6eMR1U4Hm/SZlF8IHh2iLBFtLP4kCgYBqTi1XeWeVQVSA\ny9Wolv9kMoRh/Xh6F2D8bTTybGshDVO+P4YLM4lLxh5UDZAd/VOkdf3ZIcUGv022\nlxrYbLbIEGckMCpkdHeZH/1/iuJUeiCrXeyNlQsXBrmJKr/0lENniJHGpiSEyvY5\nD8Oafyjd7ZjUmyBFvS4heQEC6Pjo3Q==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/rsa-pss-private.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIE8QIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI\nhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAEggSnMIIEowIBAAKCAQEA00tEqqyF\nVnyvcVA2ewVoSicCMdQXmWyYM82sBWX0wcnn0WUuZp1zjux4xTvQ71Lhx95OJCQZ\n7r7b2192Im5ca37wNRbI6DhyXNdNVFXLFYlNAvgP+V0gIwlr6NgopdJqHCjYVv/g\nGOoesRZaDdtV1A3O9CXdJ34x2HZh7nhwYK5hqZDhUW4rd+5GzIIzwCJfwgTQpkIc\n18UeMMEoKJ6A0ixdpf43HqJ5fAB5nsbYFhyHpfiX1UO2EFJtSdbKEIbRmqcbNjG1\ntu1tjt6u8LI2coetLh/IYMbMfkyQz+eAUHLQCUb2R8BqLOL3hRqEsVTBo93UJlOs\nVWC1fKaq+HOEWQIDAQABAoIBAAet23PagPQTjwAZcAlzjlvs5AMHQsj5gznqwSmR\nut3/e7SGrrOIXbv1iIQejZQ3w8CS/0MH/ttIRiRIaWTh9EDsjvKsU9FAxUNDiJTG\nk3LCbTFCQ7kGiJWiu4XDCWMmwmLTRzLjlMjtr/+JS5eSVPcNKMGDI3D9K0xDLSxQ\nu0DVigYgWOCWlejHCEU4yi6vBO0HlumWjVPelWb9GmihBDwCLUJtG0JA6H6rw+KS\ni6SNXcMGVKfjEghChRp+HaMvLvMgU44Ptnj8jhlfBctXInBY1is1FfDSWxXdVbUM\n1HdKXfV4A50GXSvJLiWP9ZZsaZ7NiBJK8IiJBXD72EFOzwECgYEA3RjnTJn9emzG\n84eIHZQujWWt4Tk/wjeLJYOYtAZpF7R3/fYLVypX9Bsw1IbwZodq/jChTjMaUkYt\n//FgUjF/t0uakEg1i+THPZvktNB8Q1E9NwHerB8HF/AD/jMALD+ejdLQ11Z4VScw\nzyNmSvD9I84/sgpms5YVKSH9sqww2RkCgYEA9KYws3sTfRLc1hlsS25V6+Zg3ZCk\niGcp+zrxGC1gb2/PpRvEDBucZO21KbSRuQDavWIOZYl4fGu7s8wo2oF8RxOsHQsM\nLJyjklruvtjnvuoft/bGAv2zLQkNaj+f7IgK6965gIxcLYL66UPCZZkTfL5CoJis\nV0v2hBh1ES5bLUECgYEAuONeaLxNL9dO989akAGefDePFExfePYhshk91S2XLG+J\n+CGMkjOioUsrpk3BMrwDSNU5zr8FP8/YH7OlrJYgCxN6CTWZMYb65hY7RskhYNnK\nqvkxUBYSRH49mJDlkBsTZ93nLmvs7Kh9NHqRzBGCXjLXKPdxsrPKtj7qfENqBeEC\ngYAC9dPXCCE3PTgw2wPlccNWZGY9qBdlkyH96TurmDj3gDnZ/JkFsHvW+M1dYNL2\nkx0Sd5JHBj/P+Zm+1jSUWEbBsWo+u7h8/bQ4/CKxanx7YefaWQESXjGB1P81jumH\neinvqrVB6fDfmBsjIW/DvPNwafjyaoaDU+b6uDUKbS4rQQKBgCe0pvDl5lO8FM81\nNP7GoCIu1gKBS+us1sgYE65ZFmVXJ6b5DckvobXSjM60G2N5w2xaXEXJsnwMApf1\nSClQUsgNWcSXRwL+w0pIdyFKS25BSfwUNQ9n7QLJcYgmflbARTfB3He/10vbFzTp\nG6ZAiKUp9bKFPzviII40AEPL2hPX\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "test/rsa-public-key.pem",
    "content": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ7rBa\nsuLI8AcfX5/10scSfQNCsTLV2tMKQaHuvyrVfwY0dINk+nkqB74QcT2oCCH9XduJ\njDuwWA4xLqAKuF96FsIes52opEM50W7/W7DZCKXkC8fFPFj6QF5ZzApDw2Qsu3yM\nRmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN40vXv9c4xiSafVvnx9BwYL7H1Q8NiK9L\nGEN6+JSWfgckQCs6UUBOXSZdreNN9zbQCwyzee7bOJqXUDAuLcFARzPw1EsZAyjV\ntGCKIQ0/btqK+jFunT2NBC8RItanDZpptQIDAQAB\n-----END RSA PUBLIC KEY-----\n"
  },
  {
    "path": "test/rsa-public-key.tests.js",
    "content": "const jwt = require('../');\nconst PS_SUPPORTED = require('../lib/psSupported');\nconst expect = require('chai').expect;\nconst {generateKeyPairSync} = require('crypto')\n\ndescribe('public key start with BEGIN RSA PUBLIC KEY', function () {\n\n  it('should work for RS family of algorithms', function (done) {\n    var fs = require('fs');\n    var cert_pub = fs.readFileSync(__dirname + '/rsa-public-key.pem');\n    var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');\n\n    var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});\n\n    jwt.verify(token, cert_pub, done);\n  });\n\n  it('should not work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is false or not set', function (done) {\n    const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });\n\n    expect(function() {\n      jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256'})\n    }).to.throw(Error, 'minimum key size');\n\n    done()\n  });\n\n  it('should work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is true', function (done) {\n    const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });\n\n    jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256', allowInsecureKeySizes: true}, done)\n  });\n\n  if (PS_SUPPORTED) {\n    it('should work for PS family of algorithms', function (done) {\n      var fs = require('fs');\n      var cert_pub = fs.readFileSync(__dirname + '/rsa-public-key.pem');\n      var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');\n\n      var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'PS256'});\n\n      jwt.verify(token, cert_pub, done);\n    });\n  }\n\n});\n"
  },
  {
    "path": "test/rsa-public.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzoCEC2rpSpJQaWZbUml\nsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ7rBasuLI8AcfX5/10scSfQNCsTLV2tMKQaHu\nvyrVfwY0dINk+nkqB74QcT2oCCH9XduJjDuwWA4xLqAKuF96FsIes52opEM50W7/\nW7DZCKXkC8fFPFj6QF5ZzApDw2Qsu3yMRmr7/W9uWeaTwfPx24YdY7Ah+fdLy3KN\n40vXv9c4xiSafVvnx9BwYL7H1Q8NiK9LGEN6+JSWfgckQCs6UUBOXSZdreNN9zbQ\nCwyzee7bOJqXUDAuLcFARzPw1EsZAyjVtGCKIQ0/btqK+jFunT2NBC8RItanDZpp\ntQIDAQAB\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "test/schema.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar fs = require('fs');\nvar PS_SUPPORTED = require('../lib/psSupported');\n\ndescribe('schema', function() {\n\n  describe('sign options', function() {\n    var cert_rsa_priv = fs.readFileSync(__dirname + '/rsa-private.pem');\n    var cert_ecdsa_priv = fs.readFileSync(__dirname + '/ecdsa-private.pem');\n    var cert_secp384r1_priv = fs.readFileSync(__dirname + '/secp384r1-private.pem');\n    var cert_secp521r1_priv = fs.readFileSync(__dirname + '/secp521r1-private.pem');\n\n    function sign(options, secretOrPrivateKey) {\n      jwt.sign({foo: 123}, secretOrPrivateKey, options);\n    }\n\n    it('should validate algorithm', function () {\n      expect(function () {\n        sign({ algorithm: 'foo' }, cert_rsa_priv);\n      }).to.throw(/\"algorithm\" must be a valid string enum value/);\n      sign({ algorithm: 'none' }, null);\n      sign({algorithm: 'RS256'}, cert_rsa_priv);\n      sign({algorithm: 'RS384'}, cert_rsa_priv);\n      sign({algorithm: 'RS512'}, cert_rsa_priv);\n      if (PS_SUPPORTED) {\n        sign({algorithm: 'PS256'}, cert_rsa_priv);\n        sign({algorithm: 'PS384'}, cert_rsa_priv);\n        sign({algorithm: 'PS512'}, cert_rsa_priv);\n      }\n      sign({algorithm: 'ES256'}, cert_ecdsa_priv);\n      sign({algorithm: 'ES384'}, cert_secp384r1_priv);\n      sign({algorithm: 'ES512'}, cert_secp521r1_priv);\n      sign({algorithm: 'HS256'}, 'superSecret');\n      sign({algorithm: 'HS384'}, 'superSecret');\n      sign({algorithm: 'HS512'}, 'superSecret');\n    });\n\n    it('should validate header', function () {\n      expect(function () {\n        sign({ header: 'foo' }, 'superSecret');\n      }).to.throw(/\"header\" must be an object/);\n      sign({header: {}}, 'superSecret');\n    });\n\n    it('should validate encoding', function () {\n      expect(function () {\n        sign({ encoding: 10 }, 'superSecret');\n      }).to.throw(/\"encoding\" must be a string/);\n      sign({encoding: 'utf8'},'superSecret');\n    });\n\n    it('should validate noTimestamp', function () {\n      expect(function () {\n        sign({ noTimestamp: 10 }, 'superSecret');\n      }).to.throw(/\"noTimestamp\" must be a boolean/);\n      sign({noTimestamp: true}, 'superSecret');\n    });\n  });\n\n  describe('sign payload registered claims', function() {\n\n    function sign(payload) {\n      jwt.sign(payload, 'foo123');\n    }\n\n    it('should validate exp', function () {\n      expect(function () {\n        sign({ exp: '1 monkey' });\n      }).to.throw(/\"exp\" should be a number of seconds/);\n      sign({ exp: 10.1 });\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "test/secp384r1-private.pem",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDCez58vZHVp+ArI7/fe835GAtRzE0AtrxGgQAY1U/uk2SQOaSw1ph61\n3Unr0ygS172gBwYFK4EEACKhZANiAARtwlnIqYqZxfiWR+/EM35nKHuLpOjUHiX1\nkEpSS03C9XlrBLNwLQfgjpYx9Qvqh26XAzTe74DYjcc748R+zZD2YAd3lV+OcdRE\nU+DWm4j5E6dlOXzvmw/3qxUcg3rRgR4=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "test/secp521r1-private.pem",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIHcAgEBBEIBlWXKBKKCgTgf7+NS09TMv7/NO3RtMBn9xTe+46oNNNK405lrZ9mz\nWYtlsYvkdsc2Cx3v5V8JegaCOM+XtAZ0MNKgBwYFK4EEACOhgYkDgYYABAFNzaM7\nZb9ug0p5KaZb5mjHrIshoVJSHaOXGtcjLVUakYVk0v9VsE+FKqyuLYcORUuAZdxl\nITAlC5e5JZ0o8NEKbAE+8oOrePrItR3IFBtWO15p7qiRa2dBB8oQklFrmQaJYn4K\nfDV0hYpfu6ahpRNu2akR7aMXL/vXrptCH/n64q9KjA==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "test/set_headers.tests.js",
    "content": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('set header', function() {\n\n  it('should add the header', function () {\n    var token = jwt.sign({foo: 123}, '123', { header: { foo: 'bar' } });\n    var decoded = jwt.decode(token, {complete: true});\n    expect(decoded.header.foo).to.equal('bar');\n  });\n\n  it('should allow overriding header', function () {\n    var token = jwt.sign({foo: 123}, '123', { header: { alg: 'HS512' } });\n    var decoded = jwt.decode(token, {complete: true});\n    expect(decoded.header.alg).to.equal('HS512');\n  });\n\n});\n"
  },
  {
    "path": "test/test-utils.js",
    "content": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\n\n/**\n * Correctly report errors that occur in an asynchronous callback\n * @param {function(err): void} done The mocha callback\n * @param {function(): void} testFunction The assertions function\n */\nfunction asyncCheck(done, testFunction) {\n  try {\n    testFunction();\n    done();\n  }\n  catch(err) {\n    done(err);\n  }\n}\n\n/**\n * Assert that two errors are equal\n * @param e1 {Error} The first error\n * @param e2 {Error} The second error\n */\n// chai does not do deep equality on errors: https://github.com/chaijs/chai/issues/1009\nfunction expectEqualError(e1, e2) {\n  // message and name are not always enumerable, so manually reference them\n  expect(e1.message, 'Async/Sync Error equality: message').to.equal(e2.message);\n  expect(e1.name, 'Async/Sync Error equality: name').to.equal(e2.name);\n\n  // compare other enumerable error properties\n  for(const propertyName in e1) {\n    expect(e1[propertyName], `Async/Sync Error equality: ${propertyName}`).to.deep.equal(e2[propertyName]);\n  }\n}\n\n/**\n * Base64-url encode a string\n * @param str {string} The string to encode\n * @returns {string} The encoded string\n */\nfunction base64UrlEncode(str) {\n  return Buffer.from(str).toString('base64')\n    .replace(/[=]/g, \"\")\n    .replace(/\\+/g, \"-\")\n    .replace(/\\//g, \"_\")\n  ;\n}\n\n/**\n * Verify a JWT, ensuring that the asynchronous and synchronous calls to `verify` have the same result\n * @param {string} jwtString The JWT as a string\n * @param {string} secretOrPrivateKey The shared secret or private key\n * @param {object} options Verify options\n * @param {function(err, token):void} callback\n */\nfunction verifyJWTHelper(jwtString, secretOrPrivateKey, options, callback) {\n  // freeze the time to ensure the clock remains stable across the async and sync calls\n  const fakeClock = sinon.useFakeTimers({now: Date.now()});\n  let error;\n  let syncVerified;\n  try {\n    syncVerified = jwt.verify(jwtString, secretOrPrivateKey, options);\n  }\n  catch (err) {\n    error = err;\n  }\n  jwt.verify(jwtString, secretOrPrivateKey, options, (err, asyncVerifiedToken) => {\n    try {\n      if (error) {\n        expectEqualError(err, error);\n        callback(err);\n      }\n      else {\n        expect(syncVerified, 'Async/Sync token equality').to.deep.equal(asyncVerifiedToken);\n        callback(null, syncVerified);\n      }\n    }\n    finally {\n      if (fakeClock) {\n        fakeClock.restore();\n      }\n    }\n  });\n}\n\n/**\n * Sign a payload to create a JWT, ensuring that the asynchronous and synchronous calls to `sign` have the same result\n * @param {object} payload The JWT payload\n * @param {string} secretOrPrivateKey The shared secret or private key\n * @param {object} options Sign options\n * @param {function(err, token):void} callback\n */\nfunction signJWTHelper(payload, secretOrPrivateKey, options, callback) {\n  // freeze the time to ensure the clock remains stable across the async and sync calls\n  const fakeClock = sinon.useFakeTimers({now: Date.now()});\n  let error;\n  let syncSigned;\n  try {\n    syncSigned = jwt.sign(payload, secretOrPrivateKey, options);\n  }\n  catch (err) {\n    error = err;\n  }\n  jwt.sign(payload, secretOrPrivateKey, options, (err, asyncSigned) => {\n    fakeClock.restore();\n    if (error) {\n      expectEqualError(err, error);\n      callback(err);\n    }\n    else {\n      expect(syncSigned, 'Async/Sync token equality').to.equal(asyncSigned);\n      callback(null, syncSigned);\n    }\n  });\n}\n\nmodule.exports = {\n  asyncCheck,\n  base64UrlEncode,\n  signJWTHelper,\n  verifyJWTHelper,\n};\n"
  },
  {
    "path": "test/undefined_secretOrPublickey.tests.js",
    "content": "var jwt = require('../index');\nvar JsonWebTokenError = require('../lib/JsonWebTokenError');\nvar expect = require('chai').expect;\n\nvar TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M';\n\ndescribe('verifying without specified secret or public key', function () {\n  it('should not verify null', function () {\n    expect(function () {\n      jwt.verify(TOKEN, null);\n    }).to.throw(JsonWebTokenError, /secret or public key must be provided/);\n  });\n\n  it('should not verify undefined', function () {\n    expect(function () {\n      jwt.verify(TOKEN);\n    }).to.throw(JsonWebTokenError, /secret or public key must be provided/);\n  });\n});"
  },
  {
    "path": "test/validateAsymmetricKey.tests.js",
    "content": "const validateAsymmetricKey = require('../lib/validateAsymmetricKey');\nconst PS_SUPPORTED = require('../lib/psSupported');\nconst ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('../lib/asymmetricKeyDetailsSupported');\nconst RSA_PSS_KEY_DETAILS_SUPPORTED = require('../lib/rsaPssKeyDetailsSupported');\nconst fs = require('fs');\nconst path = require('path');\nconst { createPrivateKey } = require('crypto');\nconst expect = require('chai').expect;\n\nfunction loadKey(filename) {\n  return createPrivateKey(\n    fs.readFileSync(path.join(__dirname, filename))\n  );\n}\n\nconst algorithmParams = {\n  RS256: {\n    invalidPrivateKey: loadKey('secp384r1-private.pem')\n  },\n  ES256: {\n    invalidPrivateKey: loadKey('priv.pem')\n  }\n};\n\nif (PS_SUPPORTED) {\n  algorithmParams.PS256 = {\n    invalidPrivateKey: loadKey('secp384r1-private.pem')\n  };\n}\n\ndescribe('Asymmetric key validation', function() {\n  Object.keys(algorithmParams).forEach(function(algorithm) {\n    describe(algorithm, function() {\n      const keys = algorithmParams[algorithm];\n\n      describe('when validating a key with an invalid private key type', function () {\n        it('should throw an error', function () {\n          const expectedErrorMessage = /\"alg\" parameter for \"[\\w\\d-]+\" key type must be one of:/;\n\n          expect(function() {\n            validateAsymmetricKey(algorithm, keys.invalidPrivateKey);\n          }).to.throw(expectedErrorMessage);\n        });\n      });\n    });\n  });\n\n  describe('when the function has missing parameters', function() {\n    it('should pass the validation if no key has been provided', function() {\n      const algorithm = 'ES256';\n      validateAsymmetricKey(algorithm);\n    });\n\n    it('should pass the validation if no algorithm has been provided', function() {\n      const key = loadKey('dsa-private.pem');\n      validateAsymmetricKey(null, key);\n    });\n  });\n\n  describe('when validating a key with an unsupported type', function () {\n    it('should throw an error', function() {\n      const algorithm = 'RS256';\n      const key = loadKey('dsa-private.pem');\n      const expectedErrorMessage = 'Unknown key type \"dsa\".';\n\n      expect(function() {\n        validateAsymmetricKey(algorithm, key);\n      }).to.throw(expectedErrorMessage);\n    });\n  });\n\n  describe('Elliptic curve algorithms', function () {\n    const curvesAlgorithms = [\n      { algorithm: 'ES256', curve: 'prime256v1' },\n      { algorithm: 'ES384', curve: 'secp384r1' },\n      { algorithm: 'ES512', curve: 'secp521r1' },\n    ];\n\n    const curvesKeys = [\n      { curve: 'prime256v1', key: loadKey('prime256v1-private.pem') },\n      { curve: 'secp384r1', key: loadKey('secp384r1-private.pem') },\n      { curve: 'secp521r1', key: loadKey('secp521r1-private.pem') }\n    ];\n\n    describe('when validating keys generated using Elliptic Curves', function () {\n      curvesAlgorithms.forEach(function(curveAlgorithm) {\n        curvesKeys\n          .forEach((curveKeys) => {\n            if (curveKeys.curve !== curveAlgorithm.curve) {\n              if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {\n                it(`should throw an error when validating an ${curveAlgorithm.algorithm} token for key with curve ${curveKeys.curve}`, function() {\n                  expect(() => {\n                    validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);\n                  }).to.throw(`\"alg\" parameter \"${curveAlgorithm.algorithm}\" requires curve \"${curveAlgorithm.curve}\".`);\n                });\n              } else {\n                it(`should pass the validation for incorrect keys if the Node version does not support checking the key's curve name`, function() {\n                  expect(() => {\n                    validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);\n                  }).not.to.throw();\n                });\n              }\n            } else {\n              it(`should accept an ${curveAlgorithm.algorithm} token for key with curve ${curveKeys.curve}`, function() {\n                expect(() => {\n                  validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);\n                }).not.to.throw();\n              });\n            }\n          });\n      });\n    });\n  });\n\n  if (RSA_PSS_KEY_DETAILS_SUPPORTED) {\n    describe('RSA-PSS algorithms', function () {\n      const key = loadKey('rsa-pss-private.pem');\n\n      it(`it should throw an error when validating a key with wrong RSA-RSS parameters`, function () {\n        const algorithm = 'PS512';\n        expect(function() {\n          validateAsymmetricKey(algorithm, key);\n        }).to.throw('Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of \"alg\" PS512')\n      });\n\n      it(`it should throw an error when validating a key with invalid salt length`, function () {\n        const algorithm = 'PS256';\n        const shortSaltKey = loadKey('rsa-pss-invalid-salt-length-private.pem');\n        expect(function() {\n          validateAsymmetricKey(algorithm, shortSaltKey);\n        }).to.throw('Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of \"alg\" PS256.')\n      });\n\n      it(`it should pass the validation when the key matches all the requirements for the algorithm`, function () {\n        expect(function() {\n          const algorithm = 'PS256';\n          validateAsymmetricKey(algorithm, key);\n        }).not.to.throw()\n      });\n    });\n  }\n});\n"
  },
  {
    "path": "test/verify.tests.js",
    "content": "const jwt = require('../index');\nconst jws = require('jws');\nconst fs = require('fs');\nconst path = require('path');\nconst sinon = require('sinon');\nconst JsonWebTokenError = require('../lib/JsonWebTokenError');\n\nconst assert = require('chai').assert;\nconst expect = require('chai').expect;\n\ndescribe('verify', function() {\n  const pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));\n  const priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));\n\n  it('should first assume JSON claim set', function (done) {\n    const header = { alg: 'RS256' };\n    const payload = { iat: Math.floor(Date.now() / 1000 ) };\n\n    const signed = jws.sign({\n      header: header,\n      payload: payload,\n      secret: priv,\n      encoding: 'utf8'\n    });\n\n    jwt.verify(signed, pub, {typ: 'JWT'}, function(err, p) {\n      assert.isNull(err);\n      assert.deepEqual(p, payload);\n      done();\n    });\n  });\n\n  it('should not be able to verify unsigned token', function () {\n    const header = { alg: 'none' };\n    const payload = { iat: Math.floor(Date.now() / 1000 ) };\n\n    const signed = jws.sign({\n      header: header,\n      payload: payload,\n      secret: 'secret',\n      encoding: 'utf8'\n    });\n\n    expect(function () {\n      jwt.verify(signed, 'secret', {typ: 'JWT'});\n    }).to.throw(JsonWebTokenError, /jwt signature is required/);\n  });\n\n  it('should not be able to verify unsigned token', function () {\n    const header = { alg: 'none' };\n    const payload = { iat: Math.floor(Date.now() / 1000 ) };\n\n    const signed = jws.sign({\n      header: header,\n      payload: payload,\n      secret: 'secret',\n      encoding: 'utf8'\n    });\n\n    expect(function () {\n      jwt.verify(signed, undefined, {typ: 'JWT'});\n    }).to.throw(JsonWebTokenError, /please specify \"none\" in \"algorithms\" to verify unsigned tokens/);\n  });\n\n  it('should be able to verify unsigned token when none is specified', function (done) {\n    const header = { alg: 'none' };\n    const payload = { iat: Math.floor(Date.now() / 1000 ) };\n\n    const signed = jws.sign({\n      header: header,\n      payload: payload,\n      secret: 'secret',\n      encoding: 'utf8'\n    });\n\n    jwt.verify(signed, null, {typ: 'JWT', algorithms: ['none']}, function(err, p) {\n      assert.isNull(err);\n      assert.deepEqual(p, payload);\n      done();\n    });\n  });\n\n  it('should not mutate options', function (done) {\n    const header = { alg: 'HS256' };\n    const payload = { iat: Math.floor(Date.now() / 1000 ) };\n    const  options = { typ: 'JWT' };\n    const signed = jws.sign({\n      header: header,\n      payload: payload,\n      secret: 'secret',\n      encoding: 'utf8'\n    });\n\n    jwt.verify(signed, 'secret', options, function(err) {\n      assert.isNull(err);\n      assert.deepEqual(Object.keys(options).length, 1);\n      done();\n    });\n  });\n\n  describe('secret or token as callback', function () {\n    const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MzcwMTg1ODIsImV4cCI6MTQzNzAxODU5Mn0.3aR3vocmgRpG05rsI9MpR6z2T_BGtMQaPq2YR6QaroU';\n    const key = 'key';\n\n    const payload = { foo: 'bar', iat: 1437018582, exp: 1437018592 };\n    const options = {algorithms: ['HS256'], ignoreExpiration: true};\n\n    it('without callback', function (done) {\n      jwt.verify(token, key, options, function (err, p) {\n        assert.isNull(err);\n        assert.deepEqual(p, payload);\n        done();\n      });\n    });\n\n    it('simple callback', function (done) {\n      const keyFunc = function(header, callback) {\n        assert.deepEqual(header, { alg: 'HS256', typ: 'JWT' });\n\n        callback(undefined, key);\n      };\n\n      jwt.verify(token, keyFunc, options, function (err, p) {\n        assert.isNull(err);\n        assert.deepEqual(p, payload);\n        done();\n      });\n    });\n\n    it('should error if called synchronously', function (done) {\n      const keyFunc = function(header, callback) {\n        callback(undefined, key);\n      };\n\n      expect(function () {\n        jwt.verify(token, keyFunc, options);\n      }).to.throw(JsonWebTokenError, /verify must be called asynchronous if secret or public key is provided as a callback/);\n\n      done();\n    });\n\n    it('simple error', function (done) {\n      const keyFunc = function(header, callback) {\n        callback(new Error('key not found'));\n      };\n\n      jwt.verify(token, keyFunc, options, function (err, p) {\n        assert.equal(err.name, 'JsonWebTokenError');\n        assert.match(err.message, /error in secret or public key callback/);\n        assert.isUndefined(p);\n        done();\n      });\n    });\n\n    it('delayed callback', function (done) {\n      const keyFunc = function(header, callback) {\n        setTimeout(function() {\n          callback(undefined, key);\n        }, 25);\n      };\n\n      jwt.verify(token, keyFunc, options, function (err, p) {\n        assert.isNull(err);\n        assert.deepEqual(p, payload);\n        done();\n      });\n    });\n\n    it('delayed error', function (done) {\n      const keyFunc = function(header, callback) {\n        setTimeout(function() {\n          callback(new Error('key not found'));\n        }, 25);\n      };\n\n      jwt.verify(token, keyFunc, options, function (err, p) {\n        assert.equal(err.name, 'JsonWebTokenError');\n        assert.match(err.message, /error in secret or public key callback/);\n        assert.isUndefined(p);\n        done();\n      });\n    });\n  });\n\n  describe('expiration', function () {\n    // { foo: 'bar', iat: 1437018582, exp: 1437018592 }\n    const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MzcwMTg1ODIsImV4cCI6MTQzNzAxODU5Mn0.3aR3vocmgRpG05rsI9MpR6z2T_BGtMQaPq2YR6QaroU';\n    const key = 'key';\n\n    let clock;\n    afterEach(function () {\n      try { clock.restore(); } catch (e) {}\n    });\n\n    it('should error on expired token', function (done) {\n      clock = sinon.useFakeTimers(1437018650000); // iat + 58s, exp + 48s\n      const options = {algorithms: ['HS256']};\n\n      jwt.verify(token, key, options, function (err, p) {\n        assert.equal(err.name, 'TokenExpiredError');\n        assert.equal(err.message, 'jwt expired');\n        assert.equal(err.expiredAt.constructor.name, 'Date');\n        assert.equal(Number(err.expiredAt), 1437018592000);\n        assert.isUndefined(p);\n        done();\n      });\n    });\n\n    it('should not error on expired token within clockTolerance interval', function (done) {\n      clock = sinon.useFakeTimers(1437018594000); // iat + 12s, exp + 2s\n      const options = {algorithms: ['HS256'], clockTolerance: 5 }\n\n      jwt.verify(token, key, options, function (err, p) {\n        assert.isNull(err);\n        assert.equal(p.foo, 'bar');\n        done();\n      });\n    });\n\n    describe('option: clockTimestamp', function () {\n      const clockTimestamp = 1000000000;\n      it('should verify unexpired token relative to user-provided clockTimestamp', function (done) {\n        const token = jwt.sign({foo: 'bar', iat: clockTimestamp, exp: clockTimestamp + 1}, key);\n        jwt.verify(token, key, {clockTimestamp: clockTimestamp}, function (err) {\n          assert.isNull(err);\n          done();\n        });\n      });\n      it('should error on expired token relative to user-provided clockTimestamp', function (done) {\n        const token = jwt.sign({foo: 'bar', iat: clockTimestamp, exp: clockTimestamp + 1}, key);\n        jwt.verify(token, key, {clockTimestamp: clockTimestamp + 1}, function (err, p) {\n          assert.equal(err.name, 'TokenExpiredError');\n          assert.equal(err.message, 'jwt expired');\n          assert.equal(err.expiredAt.constructor.name, 'Date');\n          assert.equal(Number(err.expiredAt), (clockTimestamp + 1) * 1000);\n          assert.isUndefined(p);\n          done();\n        });\n      });\n      it('should verify clockTimestamp is a number', function (done) {\n        const token = jwt.sign({foo: 'bar', iat: clockTimestamp, exp: clockTimestamp + 1}, key);\n        jwt.verify(token, key, {clockTimestamp: 'notANumber'}, function (err, p) {\n          assert.equal(err.name, 'JsonWebTokenError');\n          assert.equal(err.message,'clockTimestamp must be a number');\n          assert.isUndefined(p);\n          done();\n        });\n      });\n    });\n\n    describe('option: maxAge and clockTimestamp', function () {\n      // { foo: 'bar', iat: 1437018582, exp: 1437018800 } exp = iat + 218s\n      const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MzcwMTg1ODIsImV4cCI6MTQzNzAxODgwMH0.AVOsNC7TiT-XVSpCpkwB1240izzCIJ33Lp07gjnXVpA';\n      it('cannot be more permissive than expiration', function (done) {\n        const clockTimestamp = 1437018900;  // iat + 318s (exp: iat + 218s)\n        const options = {algorithms: ['HS256'], clockTimestamp: clockTimestamp, maxAge: '1000y'};\n\n        jwt.verify(token, key, options, function (err, p) {\n          // maxAge not exceded, but still expired\n          assert.equal(err.name, 'TokenExpiredError');\n          assert.equal(err.message, 'jwt expired');\n          assert.equal(err.expiredAt.constructor.name, 'Date');\n          assert.equal(Number(err.expiredAt), 1437018800000);\n          assert.isUndefined(p);\n          done();\n        });\n      });\n    });\n  });\n\n  describe('when verifying a token with an unsupported public key type', function () {\n    it('should throw an error', function() {\n      const token = 'eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2Njk5OTAwMDN9.YdjFWJtPg_9nccMnTfQyesWQ0UX-GsWrfCGit_HqjeIkNjoV6dkAJ8AtbnVEhA4oxwqSXx6ilMOfHEjmMlPtyyyVKkWKQHcIWYnqPbNSEv8a7Men8KhJTIWb4sf5YbhgSCpNvU_VIZjLO1Z0PzzgmEikp0vYbxZFAbCAlZCvUlcIc-kdjIRCnDJe0BBrYRxNLEJtYsf7D1yFIFIqw8-VP87yZdExA4eHsTaE84SgnL24ZK5h5UooDx-IRNd_rrMyio8kNy63grVxCWOtkXZ26iZk6v-HMsnBqxvUwR6-8wfaWrcpADkyUO1q3SNsoTdwtflbvfwgjo3uve0IvIzHMw';\n      const key = fs.readFileSync(path.join(__dirname, 'dsa-public.pem'));\n\n      expect(function() {\n        jwt.verify(token, key);\n      }).to.throw('Unknown key type \"dsa\".');\n    });\n  });\n\n  describe('when verifying a token with an incorrect public key type', function () {\n    it('should throw a validation error if key validation is enabled', function() {\n      const token = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXkiOiJsb2FkIiwiaWF0IjoxNjcwMjMwNDE2fQ.7TYP8SB_9Tw1fNIfuG60b4tvoLPpDAVBQpV1oepnuKwjUz8GOw4fRLzclo0Q2YAXisJ3zIYMEFsHpYrflfoZJQ';\n      const key = fs.readFileSync(path.join(__dirname, 'rsa-public.pem'));\n\n      expect(function() {\n        jwt.verify(token, key, { algorithms: ['ES256'] });\n      }).to.throw('\"alg\" parameter for \"rsa\" key type must be one of: RS256, PS256, RS384, PS384, RS512, PS512.');\n    });\n\n    it('should throw an unknown error if key validation is disabled', function() {\n      const token = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXkiOiJsb2FkIiwiaWF0IjoxNjcwMjMwNDE2fQ.7TYP8SB_9Tw1fNIfuG60b4tvoLPpDAVBQpV1oepnuKwjUz8GOw4fRLzclo0Q2YAXisJ3zIYMEFsHpYrflfoZJQ';\n      const key = fs.readFileSync(path.join(__dirname, 'rsa-public.pem'));\n\n      expect(function() {\n        jwt.verify(token, key, { algorithms: ['ES256'], allowInvalidAsymmetricKeyTypes: true });\n      }).to.not.throw('\"alg\" parameter for \"rsa\" key type must be one of: RS256, PS256, RS384, PS384, RS512, PS512.');\n    });\n  });\n});\n"
  },
  {
    "path": "test/wrong_alg.tests.js",
    "content": "var fs = require('fs');\nvar path = require('path');\nvar jwt = require('../index');\nvar JsonWebTokenError = require('../lib/JsonWebTokenError');\nvar PS_SUPPORTED = require('../lib/psSupported');\nvar expect = require('chai').expect;\n\n\nvar pub = fs.readFileSync(path.join(__dirname, 'pub.pem'), 'utf8');\n// priv is never used\n// var priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));\n\nvar TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE0MjY1NDY5MTl9.ETgkTn8BaxIX4YqvUWVFPmum3moNZ7oARZtSBXb_vP4';\n\ndescribe('when setting a wrong `header.alg`', function () {\n\n  describe('signing with pub key as symmetric', function () {\n    it('should not verify', function () {\n      expect(function () {\n        jwt.verify(TOKEN, pub);\n      }).to.throw(JsonWebTokenError, /invalid algorithm/);\n    });\n  });\n\n  describe('signing with pub key as HS256 and whitelisting only RS256', function () {\n    it('should not verify', function () {\n      expect(function () {\n        jwt.verify(TOKEN, pub, {algorithms: ['RS256']});\n      }).to.throw(JsonWebTokenError, /invalid algorithm/);\n    });\n  });\n\n  if (PS_SUPPORTED) {\n    describe('signing with pub key as HS256 and whitelisting only PS256', function () {\n      it('should not verify', function () {\n        expect(function () {\n          jwt.verify(TOKEN, pub, {algorithms: ['PS256']});\n        }).to.throw(JsonWebTokenError, /invalid algorithm/);\n      });\n    });\n  }\n\n  describe('signing with HS256 and checking with HS384', function () {\n    it('should not verify', function () {\n      expect(function () {\n        var token = jwt.sign({foo: 'bar'}, 'secret', {algorithm: 'HS256'});\n        jwt.verify(token, 'some secret', {algorithms: ['HS384']});\n      }).to.throw(JsonWebTokenError, /invalid algorithm/);\n    });\n  });\n\n\n});\n"
  },
  {
    "path": "verify.js",
    "content": "const JsonWebTokenError = require('./lib/JsonWebTokenError');\nconst NotBeforeError = require('./lib/NotBeforeError');\nconst TokenExpiredError = require('./lib/TokenExpiredError');\nconst decode = require('./decode');\nconst timespan = require('./lib/timespan');\nconst validateAsymmetricKey = require('./lib/validateAsymmetricKey');\nconst PS_SUPPORTED = require('./lib/psSupported');\nconst jws = require('jws');\nconst {KeyObject, createSecretKey, createPublicKey} = require(\"crypto\");\n\nconst PUB_KEY_ALGS = ['RS256', 'RS384', 'RS512'];\nconst EC_KEY_ALGS = ['ES256', 'ES384', 'ES512'];\nconst RSA_KEY_ALGS = ['RS256', 'RS384', 'RS512'];\nconst HS_ALGS = ['HS256', 'HS384', 'HS512'];\n\nif (PS_SUPPORTED) {\n  PUB_KEY_ALGS.splice(PUB_KEY_ALGS.length, 0, 'PS256', 'PS384', 'PS512');\n  RSA_KEY_ALGS.splice(RSA_KEY_ALGS.length, 0, 'PS256', 'PS384', 'PS512');\n}\n\nmodule.exports = function (jwtString, secretOrPublicKey, options, callback) {\n  if ((typeof options === 'function') && !callback) {\n    callback = options;\n    options = {};\n  }\n\n  if (!options) {\n    options = {};\n  }\n\n  //clone this object since we are going to mutate it.\n  options = Object.assign({}, options);\n\n  let done;\n\n  if (callback) {\n    done = callback;\n  } else {\n    done = function(err, data) {\n      if (err) throw err;\n      return data;\n    };\n  }\n\n  if (options.clockTimestamp && typeof options.clockTimestamp !== 'number') {\n    return done(new JsonWebTokenError('clockTimestamp must be a number'));\n  }\n\n  if (options.nonce !== undefined && (typeof options.nonce !== 'string' || options.nonce.trim() === '')) {\n    return done(new JsonWebTokenError('nonce must be a non-empty string'));\n  }\n\n  if (options.allowInvalidAsymmetricKeyTypes !== undefined && typeof options.allowInvalidAsymmetricKeyTypes !== 'boolean') {\n    return done(new JsonWebTokenError('allowInvalidAsymmetricKeyTypes must be a boolean'));\n  }\n\n  const clockTimestamp = options.clockTimestamp || Math.floor(Date.now() / 1000);\n\n  if (!jwtString){\n    return done(new JsonWebTokenError('jwt must be provided'));\n  }\n\n  if (typeof jwtString !== 'string') {\n    return done(new JsonWebTokenError('jwt must be a string'));\n  }\n\n  const parts = jwtString.split('.');\n\n  if (parts.length !== 3){\n    return done(new JsonWebTokenError('jwt malformed'));\n  }\n\n  let decodedToken;\n\n  try {\n    decodedToken = decode(jwtString, { complete: true });\n  } catch(err) {\n    return done(err);\n  }\n\n  if (!decodedToken) {\n    return done(new JsonWebTokenError('invalid token'));\n  }\n\n  const header = decodedToken.header;\n  let getSecret;\n\n  if(typeof secretOrPublicKey === 'function') {\n    if(!callback) {\n      return done(new JsonWebTokenError('verify must be called asynchronous if secret or public key is provided as a callback'));\n    }\n\n    getSecret = secretOrPublicKey;\n  }\n  else {\n    getSecret = function(header, secretCallback) {\n      return secretCallback(null, secretOrPublicKey);\n    };\n  }\n\n  return getSecret(header, function(err, secretOrPublicKey) {\n    if(err) {\n      return done(new JsonWebTokenError('error in secret or public key callback: ' + err.message));\n    }\n\n    const hasSignature = parts[2].trim() !== '';\n\n    if (!hasSignature && secretOrPublicKey){\n      return done(new JsonWebTokenError('jwt signature is required'));\n    }\n\n    if (hasSignature && !secretOrPublicKey) {\n      return done(new JsonWebTokenError('secret or public key must be provided'));\n    }\n\n    if (!hasSignature && !options.algorithms) {\n      return done(new JsonWebTokenError('please specify \"none\" in \"algorithms\" to verify unsigned tokens'));\n    }\n\n    if (secretOrPublicKey != null && !(secretOrPublicKey instanceof KeyObject)) {\n      try {\n        secretOrPublicKey = createPublicKey(secretOrPublicKey);\n      } catch (_) {\n        try {\n          secretOrPublicKey = createSecretKey(typeof secretOrPublicKey === 'string' ? Buffer.from(secretOrPublicKey) : secretOrPublicKey);\n        } catch (_) {\n          return done(new JsonWebTokenError('secretOrPublicKey is not valid key material'))\n        }\n      }\n    }\n\n    if (!options.algorithms) {\n      if (secretOrPublicKey.type === 'secret') {\n        options.algorithms = HS_ALGS;\n      } else if (['rsa', 'rsa-pss'].includes(secretOrPublicKey.asymmetricKeyType)) {\n        options.algorithms = RSA_KEY_ALGS\n      } else if (secretOrPublicKey.asymmetricKeyType === 'ec') {\n        options.algorithms = EC_KEY_ALGS\n      } else {\n        options.algorithms = PUB_KEY_ALGS\n      }\n    }\n\n    if (options.algorithms.indexOf(decodedToken.header.alg) === -1) {\n      return done(new JsonWebTokenError('invalid algorithm'));\n    }\n\n    if (header.alg.startsWith('HS') && secretOrPublicKey.type !== 'secret') {\n      return done(new JsonWebTokenError((`secretOrPublicKey must be a symmetric key when using ${header.alg}`)))\n    } else if (/^(?:RS|PS|ES)/.test(header.alg) && secretOrPublicKey.type !== 'public') {\n      return done(new JsonWebTokenError((`secretOrPublicKey must be an asymmetric key when using ${header.alg}`)))\n    }\n\n    if (!options.allowInvalidAsymmetricKeyTypes) {\n      try {\n        validateAsymmetricKey(header.alg, secretOrPublicKey);\n      } catch (e) {\n        return done(e);\n      }\n    }\n\n    let valid;\n\n    try {\n      valid = jws.verify(jwtString, decodedToken.header.alg, secretOrPublicKey);\n    } catch (e) {\n      return done(e);\n    }\n\n    if (!valid) {\n      return done(new JsonWebTokenError('invalid signature'));\n    }\n\n    const payload = decodedToken.payload;\n\n    if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) {\n      if (typeof payload.nbf !== 'number') {\n        return done(new JsonWebTokenError('invalid nbf value'));\n      }\n      if (payload.nbf > clockTimestamp + (options.clockTolerance || 0)) {\n        return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));\n      }\n    }\n\n    if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {\n      if (typeof payload.exp !== 'number') {\n        return done(new JsonWebTokenError('invalid exp value'));\n      }\n      if (clockTimestamp >= payload.exp + (options.clockTolerance || 0)) {\n        return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));\n      }\n    }\n\n    if (options.audience) {\n      const audiences = Array.isArray(options.audience) ? options.audience : [options.audience];\n      const target = Array.isArray(payload.aud) ? payload.aud : [payload.aud];\n\n      const match = target.some(function (targetAudience) {\n        return audiences.some(function (audience) {\n          return audience instanceof RegExp ? audience.test(targetAudience) : audience === targetAudience;\n        });\n      });\n\n      if (!match) {\n        return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or ')));\n      }\n    }\n\n    if (options.issuer) {\n      const invalid_issuer =\n              (typeof options.issuer === 'string' && payload.iss !== options.issuer) ||\n              (Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1);\n\n      if (invalid_issuer) {\n        return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer));\n      }\n    }\n\n    if (options.subject) {\n      if (payload.sub !== options.subject) {\n        return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject));\n      }\n    }\n\n    if (options.jwtid) {\n      if (payload.jti !== options.jwtid) {\n        return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid));\n      }\n    }\n\n    if (options.nonce) {\n      if (payload.nonce !== options.nonce) {\n        return done(new JsonWebTokenError('jwt nonce invalid. expected: ' + options.nonce));\n      }\n    }\n\n    if (options.maxAge) {\n      if (typeof payload.iat !== 'number') {\n        return done(new JsonWebTokenError('iat required when maxAge is specified'));\n      }\n\n      const maxAgeTimestamp = timespan(options.maxAge, payload.iat);\n      if (typeof maxAgeTimestamp === 'undefined') {\n        return done(new JsonWebTokenError('\"maxAge\" should be a number of seconds or string representing a timespan eg: \"1d\", \"20h\", 60'));\n      }\n      if (clockTimestamp >= maxAgeTimestamp + (options.clockTolerance || 0)) {\n        return done(new TokenExpiredError('maxAge exceeded', new Date(maxAgeTimestamp * 1000)));\n      }\n    }\n\n    if (options.complete === true) {\n      const signature = decodedToken.signature;\n\n      return done(null, {\n        header: header,\n        payload: payload,\n        signature: signature\n      });\n    }\n\n    return done(null, payload);\n  });\n};\n"
  }
]