Full Code of auth0/node-jsonwebtoken for AI

master cf33b5f59a19 cached
84 files
237.0 KB
75.3k tokens
39 symbols
1 requests
Download .txt
Showing preview only (256K chars total). Download the full file or copy to clipboard to get everything.
Repository: auth0/node-jsonwebtoken
Branch: master
Commit: cf33b5f59a19
Files: 84
Total size: 237.0 KB

Directory structure:
gitextract_nrhlur7n/

├── .commitlintrc.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github/
│   └── workflows/
│       ├── commitlint.yml
│       ├── prepare-release.yml
│       ├── release.yml
│       ├── sca-scan.yml
│       └── test.yml
├── .gitignore
├── .husky/
│   └── commit-msg
├── .npmignore
├── .releaserc.json
├── CHANGELOG.md
├── CODEOWNERS
├── LICENSE
├── README.md
├── bin/
│   └── changelog
├── decode.js
├── index.js
├── lib/
│   ├── JsonWebTokenError.js
│   ├── NotBeforeError.js
│   ├── TokenExpiredError.js
│   ├── asymmetricKeyDetailsSupported.js
│   ├── psSupported.js
│   ├── rsaPssKeyDetailsSupported.js
│   ├── timespan.js
│   └── validateAsymmetricKey.js
├── opslevel.yml
├── package.json
├── sign.js
├── test/
│   ├── .eslintrc.json
│   ├── async_sign.tests.js
│   ├── buffer.tests.js
│   ├── claim-aud.test.js
│   ├── claim-exp.test.js
│   ├── claim-iat.test.js
│   ├── claim-iss.test.js
│   ├── claim-jti.test.js
│   ├── claim-nbf.test.js
│   ├── claim-private.tests.js
│   ├── claim-sub.tests.js
│   ├── decoding.tests.js
│   ├── dsa-private.pem
│   ├── dsa-public.pem
│   ├── ecdsa-private.pem
│   ├── ecdsa-public-invalid.pem
│   ├── ecdsa-public-x509.pem
│   ├── ecdsa-public.pem
│   ├── encoding.tests.js
│   ├── expires_format.tests.js
│   ├── header-kid.test.js
│   ├── invalid_exp.tests.js
│   ├── invalid_pub.pem
│   ├── issue_147.tests.js
│   ├── issue_304.tests.js
│   ├── issue_70.tests.js
│   ├── jwt.asymmetric_signing.tests.js
│   ├── jwt.hs.tests.js
│   ├── jwt.malicious.tests.js
│   ├── noTimestamp.tests.js
│   ├── non_object_values.tests.js
│   ├── option-complete.test.js
│   ├── option-maxAge.test.js
│   ├── option-nonce.test.js
│   ├── prime256v1-private.pem
│   ├── priv.pem
│   ├── pub.pem
│   ├── rsa-private.pem
│   ├── rsa-pss-invalid-salt-length-private.pem
│   ├── rsa-pss-private.pem
│   ├── rsa-public-key.pem
│   ├── rsa-public-key.tests.js
│   ├── rsa-public.pem
│   ├── schema.tests.js
│   ├── secp384r1-private.pem
│   ├── secp521r1-private.pem
│   ├── set_headers.tests.js
│   ├── test-utils.js
│   ├── undefined_secretOrPublickey.tests.js
│   ├── validateAsymmetricKey.tests.js
│   ├── verify.tests.js
│   └── wrong_alg.tests.js
└── verify.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .commitlintrc.json
================================================
{
  "extends": ["@commitlint/config-conventional"]
}


================================================
FILE: .editorconfig
================================================
[*]
indent_style = space
indent_size = 2


================================================
FILE: .eslintignore
================================================
.nyc_output/
coverage/


================================================
FILE: .eslintrc.json
================================================
{
  "root": true,
  "parserOptions": {
    "ecmaVersion": 6
  },
  "env": {
    "es6": true,
    "node": true
  },
  "rules": {
    "comma-style": "error",
    "dot-notation": "error",
    "indent": ["error", 2],
    "no-control-regex": "error",
    "no-div-regex": "error",
    "no-eval": "error",
    "no-implied-eval": "error",
    "no-invalid-regexp": "error",
    "no-trailing-spaces": "error",
    "no-undef": "error",
    "no-unused-vars": "error"
  }
}


================================================
FILE: .github/workflows/commitlint.yml
================================================
name: Lint Commits

on:
  pull_request:

jobs:
  commitlint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: '24'

      - name: Install dependencies
        run: npm install

      - name: Validate commit messages
        run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose


================================================
FILE: .github/workflows/prepare-release.yml
================================================
name: Prepare Release

on:
  push:
    branches:
      - master

concurrency:
  group: prepare-release
  cancel-in-progress: true

permissions:
  contents: write
  pull-requests: write

jobs:
  prepare:
    runs-on: ubuntu-latest
    if: "!startsWith(github.event.head_commit.message, 'chore(release):')"
    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: '24'

      - name: Install dependencies
        run: npm install

      - name: Detect Next Version
        id: version
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          NEXT_VERSION=$(npx semantic-release --dry-run --plugins @semantic-release/commit-analyzer | tee /dev/stderr | awk '/The next release version is/{print $NF}')
          echo "next=$NEXT_VERSION" >> $GITHUB_OUTPUT

      - name: Update package.json
        if: steps.version.outputs.next != ''
        run: npm version "$NEXT_VERSION" --no-git-tag-version
        env:
          NEXT_VERSION: ${{ steps.version.outputs.next }}

      - name: Update CHANGELOG.md
        if: steps.version.outputs.next != ''
        run: npx conventional-changelog-cli -p angular -i CHANGELOG.md -s

      - name: Create Pull Request
        if: steps.version.outputs.next != ''
        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: "chore(release): ${{ steps.version.outputs.next }}"
          branch: "release/v${{ steps.version.outputs.next }}"
          delete-branch: true
          title: "chore(release): ${{ steps.version.outputs.next }}"
          body: |
            This PR prepares the release of version ${{ steps.version.outputs.next }}.

            **Changes:**
            - Updated version in `package.json` to ${{ steps.version.outputs.next }}
            - Updated `CHANGELOG.md` with release notes

            **Next Steps:**
            Review and merge this PR to trigger the publish workflow.
          labels: release


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - master

permissions:
  contents: write
  issues: write
  pull-requests: write
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    if: startsWith(github.event.head_commit.message, 'chore(release):')

    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: '24'

      - name: Install dependencies
        run: npm install

      - name: Set up Python
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: "3.10"

      - name: Install Python dependencies
        shell: bash
        run: pip install boto3>=1.34.159 requests>=2.32.3 rl-deploy>=2.2.3.0 pip-system-certs>=4.0

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
        with:
          role-to-assume: ${{ secrets.PRODSEC_TOOLS_ARN }}
          aws-region: us-east-1
          mask-aws-account-id: true

      - name: Install rl-wrapper
        env:
          WRAPPER_INDEX_URL: "https://${{ secrets.PRODSEC_TOOLS_USER }}:${{ secrets.PRODSEC_TOOLS_TOKEN }}@a0us.jfrog.io/artifactory/api/pypi/python-local/simple"
        run: pip install "rl-wrapper>=1.0.0" --index-url $WRAPPER_INDEX_URL

      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_CONFIG_PROVENANCE: true
          RLSECURE_LICENSE: ${{ secrets.RLSECURE_LICENSE }}
          RLSECURE_SITE_KEY: ${{ secrets.RLSECURE_SITE_KEY }}
          SIGNAL_HANDLER_TOKEN: ${{ secrets.SIGNAL_HANDLER_TOKEN }}
          PYTHONUNBUFFERED: 1
        run: npx semantic-release


================================================
FILE: .github/workflows/sca-scan.yml
================================================
name: Snyk Scan

on:
  push:
    branches: ["master"]

jobs:
  snyk-cli:
    uses: auth0/devsecops-tooling/.github/workflows/sca-scan.yml@5246a8b59100e3eea284ce4f2e2a51b51e237380
    secrets: inherit


================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on:
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        node: [16, 18, 20, 22, 24]

    name: Test (Node ${{ matrix.node }})
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Setup Node
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version: ${{ matrix.node }}

      - name: Install dependencies
        run: npm install

      - name: Test
        run: npm test


================================================
FILE: .gitignore
================================================
node_modules
.DS_Store
.nyc_output
coverage
package-lock.json


================================================
FILE: .husky/commit-msg
================================================
npx --no -- commitlint --edit ${1}


================================================
FILE: .npmignore
================================================
opslevel.yml

================================================
FILE: .releaserc.json
================================================
{
  "branches": [
    "master"
  ],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    [
      "@semantic-release/npm",
      {
        "npmPublish": true,
        "pkgRoot": "."
      }
    ],
    [
      "@semantic-release/exec",
      {
        "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",
        "prepareCmd": "git diff --exit-code"
      }
    ],
    "@semantic-release/github"
  ]
}


================================================
FILE: CHANGELOG.md
================================================
# Change Log


All notable changes to this project will be documented in this file starting from version **v4.0.0**.
This project adheres to [Semantic Versioning](http://semver.org/).

## 9.0.3 - 2025-12-04

- updates jws version to 4.0.1.

## 9.0.2 - 2023-08-30

- security: updating semver to 7.5.4 to resolve CVE-2022-25883, closes [#921](https://github.com/auth0/node-jsonwebtoken/issues/921).
- refactor: reduce library size by using lodash specific dependencies, closes [#878](https://github.com/auth0/node-jsonwebtoken/issues/878).

## 9.0.1 - 2023-07-05

- fix(stubs): allow decode method to be stubbed

## 9.0.0 - 2022-12-21

  **Breaking changes: See [Migration from v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)**

### Breaking changes

- Removed support for Node versions 11 and below.
- The verify() function no longer accepts unsigned tokens by default. ([834503079514b72264fd13023a3b8d648afd6a16]https://github.com/auth0/node-jsonwebtoken/commit/834503079514b72264fd13023a3b8d648afd6a16)
- RSA key size must be 2048 bits or greater. ([ecdf6cc6073ea13a7e71df5fad043550f08d0fa6]https://github.com/auth0/node-jsonwebtoken/commit/ecdf6cc6073ea13a7e71df5fad043550f08d0fa6)
- Key types must be valid for the signing / verification algorithm

### Security fixes

- security: fixes `Arbitrary File Write via verify function` - CVE-2022-23529
- security: fixes `Insecure default algorithm in jwt.verify() could lead to signature validation bypass` - CVE-2022-23540
- security: fixes `Insecure implementation of key retrieval function could lead to Forgeable Public/Private Tokens from RSA to HMAC` - CVE-2022-23541
- security: fixes `Unrestricted key type could lead to legacy keys usage` - CVE-2022-23539

## 8.5.1 - 2019-03-18

### Bug fix

 - 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)

### Docs

 - README: fix markdown for algorithms table ([84e03ef70f9c44a3aef95a1dc122c8238854f683](https://github.com/auth0/node-jsonwebtoken/commit/84e03ef70f9c44a3aef95a1dc122c8238854f683))

## 8.5.0 - 2019-02-20

### New Functionality

 - 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)
 - 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)

 ### Test Improvements

 - 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)
 - 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)
 - 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)
 - 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)

### Docs

- 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)


## 8.4.0 - 2018-11-14

### New Functionality

 - 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)

### Bug Fixes

 - 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)
 - 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)

### Docs

 - Update README.md (#527) ([b76f2a80f5229ee5cde321dd2ff14aa5df16d283](https://github.com/auth0/node-jsonwebtoken/commit/b76f2a80f5229ee5cde321dd2ff14aa5df16d283)), closes [#527](https://github.com/auth0/node-jsonwebtoken/issues/527)
 - Update README.md (#538) ([1956c4006472fd285b8a85074257cbdbe9131cbf](https://github.com/auth0/node-jsonwebtoken/commit/1956c4006472fd285b8a85074257cbdbe9131cbf)), closes [#538](https://github.com/auth0/node-jsonwebtoken/issues/538)
 - 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)
 - Document NotBeforeError (#529) ([29cd654b956529e939ae8f8c30b9da7063aad501](https://github.com/auth0/node-jsonwebtoken/commit/29cd654b956529e939ae8f8c30b9da7063aad501)), closes [#529](https://github.com/auth0/node-jsonwebtoken/issues/529)

### Test Improvements

 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)
 - 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)

### CI

 - 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)
 - 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)
 - 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)


## 8.3.0 - 2018-06-11

 - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473)
 - 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)
 - 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)
 - docs:Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461)


## 8.2.2 - 2018-05-30

 - 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)
 - docs: add some clarifications (#473) ([cd33cc81f06068b9df6c224d300dc6f70d8904ab](https://github.com/auth0/node-jsonwebtoken/commit/cd33cc81f06068b9df6c224d300dc6f70d8904ab)), closes [#473](https://github.com/auth0/node-jsonwebtoken/issues/473)
 - 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)
 - docs: Update README.md (#461) ([f0e0954505f274da95a8d9603598e455b4d2c894](https://github.com/auth0/node-jsonwebtoken/commit/f0e0954505f274da95a8d9603598e455b4d2c894)), closes [#461](https://github.com/auth0/node-jsonwebtoken/issues/461)


## 8.2.1 - 2018-04-05

 - bug fix: Check payload is not null when decoded. (#444) ([1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5](https://github.com/auth0/node-jsonwebtoken/commit/1232ae9352ce5fd1ca6c593291ce6ad0834a1ff5))
 - docs: Clarify that buffer/string payloads must be JSON (#442) ([e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b](https://github.com/auth0/node-jsonwebtoken/commit/e8ac1be7565a3fd986d40cb5e31a9f6c4d9aed1b))


## 8.2.0 - 2018-03-02

 - Add a new mutatePayload option (#446) ([d6d7c5e5103f05a92d3633ac190d3025a0455be0](https://github.com/auth0/node-jsonwebtoken/commit/d6d7c5e5103f05a92d3633ac190d3025a0455be0))


## 8.1.1 - 2018-01-22

 - ci: add newer node versions to build matrix (#428) ([83f3eee44e122da06f812d7da4ace1fa26c24d9d](https://github.com/auth0/node-jsonwebtoken/commit/83f3eee44e122da06f812d7da4ace1fa26c24d9d))
 - deps: Bump ms version to add support for negative numbers (#438) ([25e0e624545eaef76f3c324a134bf103bc394724](https://github.com/auth0/node-jsonwebtoken/commit/25e0e624545eaef76f3c324a134bf103bc394724))
 - docs: Minor typo (#424) ([dddcb73ac05de11b81feeb629f6cf78dd03d2047](https://github.com/auth0/node-jsonwebtoken/commit/dddcb73ac05de11b81feeb629f6cf78dd03d2047))
 - 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)


## 8.1.0 - 2017-10-09

 - #402: Don't fail if captureStackTrace is not a function (#410) ([77ee965d9081faaf21650f266399f203f69533c5](https://github.com/auth0/node-jsonwebtoken/commit/77ee965d9081faaf21650f266399f203f69533c5))
 - #403: Clarify error wording for "Expected object" error. (#409) ([bb27eb346f0ff675a320b2de16b391a7cfeadc58](https://github.com/auth0/node-jsonwebtoken/commit/bb27eb346f0ff675a320b2de16b391a7cfeadc58))
 - Enhance audience check to verify against regular expressions (#398) ([81501a17da230af7b74a3f7535ab5cd3a19c8315](https://github.com/auth0/node-jsonwebtoken/commit/81501a17da230af7b74a3f7535ab5cd3a19c8315))


## 8.0.1 - 2017-09-12

 - Remove `lodash.isarray` dependency (#394) ([7508e8957cb1c778f72fa9a363a7b135b3c9c36d](https://github.com/auth0/node-jsonwebtoken/commit/7508e8957cb1c778f72fa9a363a7b135b3c9c36d))

## 8.0.0 - 2017-09-06

  **Breaking changes: See [Migration notes from v7](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)**

 - docs: readme, migration notes ([12cd8f7f47224f904f6b8f39d1dee73775de4f6f](https://github.com/auth0/node-jsonwebtoken/commit/12cd8f7f47224f904f6b8f39d1dee73775de4f6f))
 - verify: remove process.nextTick (#302) ([3305cf04e3f674b9fb7e27c9b14ddd159650ff82](https://github.com/auth0/node-jsonwebtoken/commit/3305cf04e3f674b9fb7e27c9b14ddd159650ff82))
 - Reduce size of NPM package (#347) ([0be5409ac6592eeaae373dce91ec992fa101bd8a](https://github.com/auth0/node-jsonwebtoken/commit/0be5409ac6592eeaae373dce91ec992fa101bd8a))
 - Remove joi to shrink module size (#348) ([2e7e68dbd59e845cdd940afae0a296f48438445f](https://github.com/auth0/node-jsonwebtoken/commit/2e7e68dbd59e845cdd940afae0a296f48438445f))
 - maxAge: Add validation to timespan result ([66a4f8b996c8357727ce62a84605a005b2f5eb18](https://github.com/auth0/node-jsonwebtoken/commit/66a4f8b996c8357727ce62a84605a005b2f5eb18))

## 7.4.3 - 2017-08-17

 - 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))

## 7.4.2 - 2017-08-04

 - bugfix: sign: add check to be sure secret has a value ([c584d1cbc34b788977b36f17cd57ab2212f1230e](https://github.com/auth0/node-jsonwebtoken/commit/c584d1cbc34b788977b36f17cd57ab2212f1230e))
 - docs: about refreshing tokens ([016fc10b847bfbb76b82171cb530f32d7da2001b](https://github.com/auth0/node-jsonwebtoken/commit/016fc10b847bfbb76b82171cb530f32d7da2001b))
 - docs: verifying with base64 encoded secrets ([c25e9906801f89605080cc71b3ee23a5e45a5811](https://github.com/auth0/node-jsonwebtoken/commit/c25e9906801f89605080cc71b3ee23a5e45a5811))
 - tests: Add tests for ES256 ([89900ea00735f76b04f437c9f542285b420fa9cb](https://github.com/auth0/node-jsonwebtoken/commit/89900ea00735f76b04f437c9f542285b420fa9cb))
 - docs: document keyid as option (#361) ([00086c2c006d7fc1a47bae02fa87d194d79aa558](https://github.com/auth0/node-jsonwebtoken/commit/00086c2c006d7fc1a47bae02fa87d194d79aa558))
 - docs: readme: Using private key with passpharase (#353) ([27a7f1d4f35b662426ff0270526d48658da4c8b7](https://github.com/auth0/node-jsonwebtoken/commit/27a7f1d4f35b662426ff0270526d48658da4c8b7))

## 7.4.1 - 2017-05-17

 - bump ms to v2 due a ReDoS vulnerability (#352) ([adcfd6ae4088c838769d169f8cd9154265aa13e0](https://github.com/auth0/node-jsonwebtoken/commit/adcfd6ae4088c838769d169f8cd9154265aa13e0))

## 7.4.0 - 2017-04-24

 - Add docs about numeric date fields ([659f73119900a4d837650d9b3f5af4e64a2f843b](https://github.com/auth0/node-jsonwebtoken/commit/659f73119900a4d837650d9b3f5af4e64a2f843b))
 - Make Options object optional for callback-ish sign ([e202c4fd00c35a24e9ab606eab89186ade13d0cc](https://github.com/auth0/node-jsonwebtoken/commit/e202c4fd00c35a24e9ab606eab89186ade13d0cc))

## 7.3.0 - 2017-02-13

 - Add more information to `maxAge` option in README ([1b0592e99cc8def293eed177e2575fa7f1cf7aa5](https://github.com/auth0/node-jsonwebtoken/commit/1b0592e99cc8def293eed177e2575fa7f1cf7aa5))
 - 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))
 - 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)
 - 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)
 - Raise jws.decode error to avoid confusion with "invalid token" error  (#294) ([7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e](https://github.com/auth0/node-jsonwebtoken/commit/7f68fe06c88d5c5653785bd66bc68c5b20e1bd8e))
 - rauchg/ms.js changed to zeit/ms (#303) ([35d84152a6b716d757cb5b1dd3c79fe3a1bc0628](https://github.com/auth0/node-jsonwebtoken/commit/35d84152a6b716d757cb5b1dd3c79fe3a1bc0628))

## 7.2.1 - 2016-12-07

 - add nsp check to find vulnerabilities on npm test ([4219c34b5346811c07f520f10516cc495bcc70dd](https://github.com/auth0/node-jsonwebtoken/commit/4219c34b5346811c07f520f10516cc495bcc70dd))
 - revert to joi@^6 to keep ES5 compatibility ([51d4796c07344bf817687f7ccfeef78f00bf5b4f](https://github.com/auth0/node-jsonwebtoken/commit/51d4796c07344bf817687f7ccfeef78f00bf5b4f))

## 7.2.0 - 2016-12-06

 - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0))
 - Restructured a sentence ([ccc7610187a862f7a50177eadc9152eef26cd065](https://github.com/auth0/node-jsonwebtoken/commit/ccc7610187a862f7a50177eadc9152eef26cd065))
 - Allow `keyid` on `sign`. ([b412be91b89acb3a742bb609d3b54e47e1dfc441](https://github.com/auth0/node-jsonwebtoken/commit/b412be91b89acb3a742bb609d3b54e47e1dfc441))
 - upgrade joi ([715e3d928023d414d45c6dc3f096a7c8448139ae](https://github.com/auth0/node-jsonwebtoken/commit/715e3d928023d414d45c6dc3f096a7c8448139ae))
 - upgrade to latest nodes and Travis infrastructure ([3febcc1dd23ecdec1abbf89313959941d15eb47a](https://github.com/auth0/node-jsonwebtoken/commit/3febcc1dd23ecdec1abbf89313959941d15eb47a))


## 7.1.10 - 2016-12-06

 - Bump node-jws version number ([07813dd7194630c9f452684279178af76464a759](https://github.com/auth0/node-jsonwebtoken/commit/07813dd7194630c9f452684279178af76464a759))
 - improve the documentation for expiration ([771e0b5f9bed90771fb79140eb38e51a3ecac8f0](https://github.com/auth0/node-jsonwebtoken/commit/771e0b5f9bed90771fb79140eb38e51a3ecac8f0))

## 7.1.9 - 2016-08-11

 - Revert "Merge branch 'venatir-master'" ([d06359ef3b4e619680e043ee7c16adda16598f52](https://github.com/auth0/node-jsonwebtoken/commit/d06359ef3b4e619680e043ee7c16adda16598f52))



## 7.1.8 - 2016-08-10

 - 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))
 - Removing unnecessary extra decoding. jwtString is already verified as valid and signature checked ([55d5834f7b637011e1d8b927ff78a92a5fd521cf](https://github.com/auth0/node-jsonwebtoken/commit/55d5834f7b637011e1d8b927ff78a92a5fd521cf))
 - update changelog ([5117aacd0118a10331889a64e61d8186112d8a23](https://github.com/auth0/node-jsonwebtoken/commit/5117aacd0118a10331889a64e61d8186112d8a23))


## 7.1.7 - 2016-07-29

 - Use lodash.once instead of unlicensed/unmaintained cb ([3ac95ad93ef3068a64e03d8d14deff231b1ed529](https://github.com/auth0/node-jsonwebtoken/commit/3ac95ad93ef3068a64e03d8d14deff231b1ed529))

## 7.1.6 - 2016-07-15

 - 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)


## 7.1.5 - 2016-07-15

 - update jws in package.json ([b6260951eefc68aae5f4ede359210761f901ff7a](https://github.com/auth0/node-jsonwebtoken/commit/b6260951eefc68aae5f4ede359210761f901ff7a))


## 7.1.4 - 2016-07-14

 - add redundant test ([bece8816096f324511c3efcb8db0e64b75d757a1](https://github.com/auth0/node-jsonwebtoken/commit/bece8816096f324511c3efcb8db0e64b75d757a1))
 - fix an issue of double callback on error ([758ca5eeca2f1b06c32c9fce70642bf488b2e52b](https://github.com/auth0/node-jsonwebtoken/commit/758ca5eeca2f1b06c32c9fce70642bf488b2e52b))

## 7.1.2 - 2016-07-12

 - 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)

## 7.1.1 - 2016-07-12

 - 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)
 - refactor into multiple files ([e11d505207fa33501298300c9accbfb809d8748d](https://github.com/auth0/node-jsonwebtoken/commit/e11d505207fa33501298300c9accbfb809d8748d))

## 7.1.0 - 2016-07-12

 - 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)

## 7.0.0 - 2016-05-19

 - change jwt.sign to return errors on callback instead of throwing errors ([1e46c5a42aa3dab8478efa4081d8f8f5c5485d56](https://github.com/auth0/node-jsonwebtoken/commit/1e46c5a42aa3dab8478efa4081d8f8f5c5485d56))

## 6.2.0 - 2016-04-29

 - add support for `options.clockTolerance` to `jwt.verify` ([65ddea934f226bf06bc9d6a55be9587515cfc38d](https://github.com/auth0/node-jsonwebtoken/commit/65ddea934f226bf06bc9d6a55be9587515cfc38d))

## 6.1.2 - 2016-04-29

 - 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)
 - improve async test ([7b0981380ddc40a5f1208df520631785b5ffb85a](https://github.com/auth0/node-jsonwebtoken/commit/7b0981380ddc40a5f1208df520631785b5ffb85a))

## 6.1.0 - 2016-04-27

 - verify unsigned tokens ([ec880791c10ed5ef7c8df7bf28ebb95c810479ed](https://github.com/auth0/node-jsonwebtoken/commit/ec880791c10ed5ef7c8df7bf28ebb95c810479ed))

## 6.0.1 - 2016-04-27

This was an immediate change after publishing 6.0.0.

 - throw error on invalid options when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))

## 6.0.0 - 2016-04-27

 - Change .sign to standard async callback ([50873c7d45d2733244d5da8afef3d1872e657a60](https://github.com/auth0/node-jsonwebtoken/commit/50873c7d45d2733244d5da8afef3d1872e657a60))
 - Improved the options for the `sign` method ([53c3987b3cc34e95eb396b26fc9b051276e2f6f9](https://github.com/auth0/node-jsonwebtoken/commit/53c3987b3cc34e95eb396b26fc9b051276e2f6f9))

    -  throw error on invalid options like `expiresIn` when the payload is not an object ([304f1b33075f79ed66f784e27dc4f5307aa39e27](https://github.com/auth0/node-jsonwebtoken/commit/304f1b33075f79ed66f784e27dc4f5307aa39e27))
    -  `expiresInMinutes` and `expiresInSeconds` are deprecated and no longer supported.
    -  `notBeforeInMinutes` and `notBeforeInSeconds` are deprecated and no longer supported.
    -  `options` are strongly validated.
    -  `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`
    -  `options.algorithm` is properly validated.
    -  `options.headers` is renamed to `options.header`.

 - 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)
 - update readme ([53a88ecf4494e30e1d62a1cf3cc354650349f486](https://github.com/auth0/node-jsonwebtoken/commit/53a88ecf4494e30e1d62a1cf3cc354650349f486))

## 5.7.0 - 2016-02-16


 - 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)


## 5.6.1 - 2016-02-16


 - 5.6.1 ([06d8209d499dbc9a8dd978ab6cbb9c6818fde203](https://github.com/auth0/node-jsonwebtoken/commit/06d8209d499dbc9a8dd978ab6cbb9c6818fde203))
 - 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)



## 5.6.0 - 2016-02-16


 - added missing validations of sub and jti ([a1affe960d0fc52e9042bcbdedb65734f8855580](https://github.com/auth0/node-jsonwebtoken/commit/a1affe960d0fc52e9042bcbdedb65734f8855580))
 - Fix tests in jwt.rs.tests.js which causes 4 to fail ([8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1](https://github.com/auth0/node-jsonwebtoken/commit/8aedf2b1f575b0d9575c1fc9f2ac7bc868f75ff1))
 - Update README.md ([349b7cd00229789b138928ca060d3ef015aedaf9](https://github.com/auth0/node-jsonwebtoken/commit/349b7cd00229789b138928ca060d3ef015aedaf9))



## 5.5.4 - 2016-01-04


 - minor ([46552e7c45025c76e3f647680d7539a66bfac612](https://github.com/auth0/node-jsonwebtoken/commit/46552e7c45025c76e3f647680d7539a66bfac612))



## 5.5.3 - 2016-01-04


 - add a console.warn on invalid options for string payloads ([71200f14deba0533d3261266348338fac2d14661](https://github.com/auth0/node-jsonwebtoken/commit/71200f14deba0533d3261266348338fac2d14661))
 - minor ([65b1f580382dc58dd3da6f47a52713776fd7cdf2](https://github.com/auth0/node-jsonwebtoken/commit/65b1f580382dc58dd3da6f47a52713776fd7cdf2))



## 5.5.2 - 2016-01-04


 - 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)



## 5.5.1 - 2016-01-04


 - fix nbf verification. fix #152 ([786d37b299c67771b5e71a2ca476666ab0f97d98](https://github.com/auth0/node-jsonwebtoken/commit/786d37b299c67771b5e71a2ca476666ab0f97d98)), closes [#152](https://github.com/auth0/node-jsonwebtoken/issues/152)



## 5.5.0 - 2015-12-28


 - improvements to nbf and jti claims ([46372e928f6d2e7398f9b88022ca617d2a3b0699](https://github.com/auth0/node-jsonwebtoken/commit/46372e928f6d2e7398f9b88022ca617d2a3b0699))
 - Remove duplicate payload line (fix bug in IE strict mode) ([8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8](https://github.com/auth0/node-jsonwebtoken/commit/8163d698e0c5ad8c44817a5dcd42a15d7e9c6bc8))
 - Remove duplicate require('ms') line ([7c00bcbcbf8f7503a1070b394a165eccd41de66f](https://github.com/auth0/node-jsonwebtoken/commit/7c00bcbcbf8f7503a1070b394a165eccd41de66f))
 - Update README to reflect addition of async sign ([d661d4b6f68eb417834c99b36769444723041ccf](https://github.com/auth0/node-jsonwebtoken/commit/d661d4b6f68eb417834c99b36769444723041ccf))



## 5.4.0 - 2015-10-02


 - deprecate expireInMinutes and expireInSeconds - in favor of expiresIn ([39ecc6f8f310f8462e082f1d53de0b4222b29b6f](https://github.com/auth0/node-jsonwebtoken/commit/39ecc6f8f310f8462e082f1d53de0b4222b29b6f))


## 5.3.0 - 2015-10-02


 - 5.3.0 ([5d559ced3fbf10c1adae2e5792deda06ea89bcd3](https://github.com/auth0/node-jsonwebtoken/commit/5d559ced3fbf10c1adae2e5792deda06ea89bcd3))
 - minor ([6e81ff87a3799b0e56db09cbae42a97e784716c4](https://github.com/auth0/node-jsonwebtoken/commit/6e81ff87a3799b0e56db09cbae42a97e784716c4))



## 5.1.0 - 2015-10-02


 - added async signing ([9414fbcb15a1f9cf4fe147d070e9424c547dabba](https://github.com/auth0/node-jsonwebtoken/commit/9414fbcb15a1f9cf4fe147d070e9424c547dabba))
 - Update README.md ([40b2aaaa843442dfb8ee7b574f0a788177e7c904](https://github.com/auth0/node-jsonwebtoken/commit/40b2aaaa843442dfb8ee7b574f0a788177e7c904))



## 5.0.5 - 2015-08-19


 - add ms dep to package.json ([f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251](https://github.com/auth0/node-jsonwebtoken/commit/f13b3fb7f29dff787e7c91ebe2eb5adeeb05f251))
 - add note to explain, related to #96 #101 #6 ([dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3](https://github.com/auth0/node-jsonwebtoken/commit/dd8969e0e6ed0bcb9cae905d2b1a96476bd85da3))
 - add tests for options.headers ([7787dd74e705787c39a871ca29c75a2e0a3948ac](https://github.com/auth0/node-jsonwebtoken/commit/7787dd74e705787c39a871ca29c75a2e0a3948ac))
 - add tests for verify expires ([d7c5793d98c300603440ab460c11665f661ad3a0](https://github.com/auth0/node-jsonwebtoken/commit/d7c5793d98c300603440ab460c11665f661ad3a0))
 - add verify option maxAge (with tests) ([49d54e54f7e70b1c53a2e4ee67e116c907d75319](https://github.com/auth0/node-jsonwebtoken/commit/49d54e54f7e70b1c53a2e4ee67e116c907d75319))
 - fix spelling error in error message ([8078b11b224fa05ac9003ca5aa2c85e9f0128cfb](https://github.com/auth0/node-jsonwebtoken/commit/8078b11b224fa05ac9003ca5aa2c85e9f0128cfb))
 - Fix typo options.header is not a documented option + ([5feaa5b962ccbddeff054817a410f7b0c1e6ce7f](https://github.com/auth0/node-jsonwebtoken/commit/5feaa5b962ccbddeff054817a410f7b0c1e6ce7f))
 - 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)


## 5.0.3 - 2015-07-15

 - Added nbf support ([f26ba4e2fa197a20497632b63ffcd13ae93aacc4](https://github.com/auth0/node-jsonwebtoken/commit/f26ba4e2fa197a20497632b63ffcd13ae93aacc4))
 - Added support for subject and jwt id ([ab76ec5bc554e2d1e25376ddb7cea711d86af651](https://github.com/auth0/node-jsonwebtoken/commit/ab76ec5bc554e2d1e25376ddb7cea711d86af651))
 - Fix `this` referring to the global object instead of `module.exports` in `verify()` ([93f554312e37129027fcf4916f48cb8d1b53588c](https://github.com/auth0/node-jsonwebtoken/commit/93f554312e37129027fcf4916f48cb8d1b53588c))
 - Fix typo, line 139 README, complete option for .decode. ([59c110aeb8c7c1847ef2ffd77702d13627c89e10](https://github.com/auth0/node-jsonwebtoken/commit/59c110aeb8c7c1847ef2ffd77702d13627c89e10))
 - minor ([61ff1172272b582902313e958058ff22413494af](https://github.com/auth0/node-jsonwebtoken/commit/61ff1172272b582902313e958058ff22413494af))



## 5.0.2 - 2015-06-15


 - 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)



## 5.0.1 - 2015-05-15


 - Add option to return header and payload when decoding. ([7254e011b59f892d1947e6c11819281adac7069d](https://github.com/auth0/node-jsonwebtoken/commit/7254e011b59f892d1947e6c11819281adac7069d))
 - Avoid uncaught "SyntaxError: Unexpected token ͧ" error. ([0dc59cd6ee15d83a606acffa7909ee76176ae186](https://github.com/auth0/node-jsonwebtoken/commit/0dc59cd6ee15d83a606acffa7909ee76176ae186))
 - Document complete option in README. ([ec32b20241a74d9681ea26e1a7024b4642468c00](https://github.com/auth0/node-jsonwebtoken/commit/ec32b20241a74d9681ea26e1a7024b4642468c00))
 - Fix example in README, silence verbose logging. ([ba3174d10033c41e9c211a38f1cc67f74fbd7f69](https://github.com/auth0/node-jsonwebtoken/commit/ba3174d10033c41e9c211a38f1cc67f74fbd7f69))
 - Fix link to auth0.com in README ([1b3c5ff72c9bc25e9271646e679f3080f2a042a0](https://github.com/auth0/node-jsonwebtoken/commit/1b3c5ff72c9bc25e9271646e679f3080f2a042a0))
 - Immediate return if not decoded. ([851bda2b10168f3269c3da6e74d310742f31a193](https://github.com/auth0/node-jsonwebtoken/commit/851bda2b10168f3269c3da6e74d310742f31a193))
 - Prevent throw on undefined/null secret ([0fdf78d4dbf609455f3277d6169a987aef0384d4](https://github.com/auth0/node-jsonwebtoken/commit/0fdf78d4dbf609455f3277d6169a987aef0384d4))
 - Removed path from test ([d6240e24186732d368bffe21143becf44c38f0d6](https://github.com/auth0/node-jsonwebtoken/commit/d6240e24186732d368bffe21143becf44c38f0d6))
 - Simplified checking for missing key ([f1cffd033bffc44f20558eda4a797c3fa2f4ee05](https://github.com/auth0/node-jsonwebtoken/commit/f1cffd033bffc44f20558eda4a797c3fa2f4ee05))
 - Typo ([ffe68dbe0219bab535c1018448eb4c0b22f1f902](https://github.com/auth0/node-jsonwebtoken/commit/ffe68dbe0219bab535c1018448eb4c0b22f1f902))
 - Update CHANGELOG.md ([927cce0dad1bc9aad75aeef53e276cf4cfc0d776](https://github.com/auth0/node-jsonwebtoken/commit/927cce0dad1bc9aad75aeef53e276cf4cfc0d776))
 - Update CHANGELOG.md ([6879e0fdde222995c70a3a69a4af94993d9c667e](https://github.com/auth0/node-jsonwebtoken/commit/6879e0fdde222995c70a3a69a4af94993d9c667e))
 - Update CHANGELOG.md ([c5596c10e8705727fa13e0394184a606083078bc](https://github.com/auth0/node-jsonwebtoken/commit/c5596c10e8705727fa13e0394184a606083078bc))
 - Update CHANGELOG.md ([07541f0315f26d179e1cde92732b6124d6869b6f](https://github.com/auth0/node-jsonwebtoken/commit/07541f0315f26d179e1cde92732b6124d6869b6f))
 - Update CHANGELOG.md ([e6465d48ddd1dc2c3297229b28c78fd5490a2ba9](https://github.com/auth0/node-jsonwebtoken/commit/e6465d48ddd1dc2c3297229b28c78fd5490a2ba9))

## [5.0.0] - 2015-04-11

### Changed

 - [sign] Only set defautl `iat` if the user does not specify that argument.

  https://github.com/auth0/node-jsonwebtoken/commit/e900282a8d2dff1d4dec815f7e6aa7782e867d91
  https://github.com/auth0/node-jsonwebtoken/commit/35036b188b4ee6b42df553bbb93bc8a6b19eae9d
  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9
  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e
  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516

### Security

 - [verify] Update to jws@^3.0.0 and renaming `header.alg` mismatch exception to `invalid algorithm` and adding more mismatch tests.

  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`

 As the order of steps has changed, the error that was thrown when the JWT was invalid is no longer the `jws` one:
 ```
 { [Error: Invalid token: no header in signature 'a.b.c'] code: 'MISSING_HEADER', signature: 'a.b.c' }
 ```

 That old error (removed from jws) has been replaced by a `JsonWebTokenError` with message `invalid token`.

 > 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`.

  https://github.com/auth0/node-jsonwebtoken/commit/634b8ed0ff5267dc25da5c808634208af109824e
  https://github.com/auth0/node-jsonwebtoken/commit/9f24ffd5791febb449d4d03ff58d7807da9b9b7e
  https://github.com/auth0/node-jsonwebtoken/commit/19e6cc6a1f2fd90356f89b074223b9665f2aa8a2
  https://github.com/auth0/node-jsonwebtoken/commit/1e4623420159c6410616f02a44ed240f176287a9
  https://github.com/auth0/node-jsonwebtoken/commit/954bd7a312934f03036b6bb6f00edd41f29e54d9
  https://github.com/auth0/node-jsonwebtoken/commit/24a370080e0b75f11d4717cd2b11b2949d95fc2e
  https://github.com/auth0/node-jsonwebtoken/commit/a77df6d49d4ec688dfd0a1cc723586bffe753516

## [4.2.2] - 2015-03-26
### Fixed

 - [asymmetric-keys] Fix verify for RSAPublicKey formated keys (`jfromaniello - awlayton`)
  https://github.com/auth0/node-jsonwebtoken/commit/402794663b9521bf602fcc6f2e811e7d3912f9dc
  https://github.com/auth0/node-jsonwebtoken/commit/8df6aabbc7e1114c8fb3917931078254eb52c222

## [4.2.1] - 2015-03-17
### Fixed

 - [asymmetric-keys] Fixed issue when public key starts with BEING PUBLIC KEY (https://github.com/auth0/node-jsonwebtoken/issues/70) (`jfromaniello`)
  https://github.com/auth0/node-jsonwebtoken/commit/7017e74db9b194448ff488b3e16468ada60c4ee5

## [4.2.0] - 2015-03-16
### Security

 - [asymmetric-keys] Making sure a token signed with an asymmetric key will be verified using a asymmetric key.
   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).

  The issue was caused because the same signature was used to verify both type of tokens (`verify` method parameter: `secretOrPublicKey`).

  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`)
  https://github.com/auth0/node-jsonwebtoken/commit/c2bf7b2cd7e8daf66298c2d168a008690bc4bdd3
  https://github.com/auth0/node-jsonwebtoken/commit/1bb584bc382295eeb7ee8c4452a673a77a68b687

## [4.1.0] - 2015-03-10
### Changed
- Assume the payload is JSON even when there is no `typ` property. [5290db1](https://github.com/auth0/node-jsonwebtoken/commit/5290db1bd74f74cd38c90b19e2355ef223a4d931)

## [4.0.0] - 2015-03-06
### Changed
- The default encoding is now utf8 instead of binary. [92d33bd](https://github.com/auth0/node-jsonwebtoken/commit/92d33bd99a3416e9e5a8897d9ad8ff7d70a00bfd)
- Add `encoding` as a new option to `sign`. [1fc385e](https://github.com/auth0/node-jsonwebtoken/commit/1fc385ee10bd0018cd1441552dce6c2e5a16375f)
- Add `ignoreExpiration` to `verify`. [8d4da27](https://github.com/auth0/node-jsonwebtoken/commit/8d4da279e1b351ac71ace276285c9255186d549f)
- Add `expiresInSeconds` to `sign`. [dd156cc](https://github.com/auth0/node-jsonwebtoken/commit/dd156cc30f17028744e60aec0502897e34609329)

### Fixed
- Fix wrong error message when the audience doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)
- Fix wrong error message when the issuer doesn't match. [44e3c8d](https://github.com/auth0/node-jsonwebtoken/commit/44e3c8d757e6b4e2a57a69a035f26b4abec3e327)
- Fix wrong `iat` and `exp` values when signing with `noTimestamp`. [331b7bc](https://github.com/auth0/node-jsonwebtoken/commit/331b7bc9cc335561f8806f2c4558e105cb53e0a6)


================================================
FILE: CODEOWNERS
================================================
* @auth0/project-iam-protocols-engineer-codeowner


================================================
FILE: LICENSE
================================================
The MIT License (MIT)
 
Copyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# jsonwebtoken

| **Build**                                                                                                                               | **Dependency**                                                                                                         |
|-----------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| [![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) |


An implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519).

This was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws)

# Install

```bash
$ npm install jsonwebtoken
```

# Migration notes

* [From v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)
* [From v7 to v8](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)

# Usage

### jwt.sign(payload, secretOrPrivateKey, [options, callback])

(Asynchronous) If a callback is supplied, the callback is called with the `err` or the JWT.

(Synchronous) Returns the JsonWebToken as string

`payload` could be an object literal, buffer or string representing valid JSON. 
> **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.

> If `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`.

`secretOrPrivateKey` is a string (utf-8 encoded), buffer, object, or KeyObject containing either the secret for HMAC algorithms or the PEM
encoded 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.
When 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.

`options`:

* `algorithm` (default: `HS256`)
* `expiresIn`: expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms). 
  > 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"`).
* `notBefore`: expressed in seconds or a string describing a time span [vercel/ms](https://github.com/vercel/ms). 
  > 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"`).
* `audience`
* `issuer`
* `jwtid`
* `subject`
* `noTimestamp`
* `header`
* `keyid`
* `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.
* `allowInsecureKeySizes`: if true allows private keys with a modulus below 2048 to be used for RSA
* `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.



> 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.

Remember that `exp`, `nbf` and `iat` are **NumericDate**, see related [Token Expiration (exp claim)](#token-expiration-exp-claim)


The header can be customized via the `options.header` object.

Generated 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`.

Synchronous Sign with default (HMAC SHA256)

```js
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
```

Synchronous Sign with RSA SHA256
```js
// sign with RSA SHA256
var privateKey = fs.readFileSync('private.key');
var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });
```

Sign asynchronously
```js
jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) {
  console.log(token);
});
```

Backdate a jwt 30 seconds
```js
var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');
```

#### Token Expiration (exp claim)

The standard for JWT defines an `exp` claim for expiration. The expiration is represented as a **NumericDate**:

> 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.

This means that the `exp` field should contain the number of seconds since the epoch.

Signing a token with 1 hour of expiration:

```javascript
jwt.sign({
  exp: Math.floor(Date.now() / 1000) + (60 * 60),
  data: 'foobar'
}, 'secret');
```

Another way to generate a token like this with this library is:

```javascript
jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: 60 * 60 });

//or even better:

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: '1h' });
```

### jwt.verify(token, secretOrPublicKey, [options, callback])

(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.

(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.

> __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

`token` is the JsonWebToken string

`secretOrPublicKey` is a string (utf-8 encoded), buffer, or KeyObject containing either the secret for HMAC algorithms, or the PEM
encoded public key for RSA and ECDSA.
If `jwt.verify` is called asynchronous, `secretOrPublicKey` can be a function that should fetch the secret or public key. See below for a detailed example

As 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.

`options`

* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `["HS256", "HS384"]`. 
  > If not specified a defaults will be used based on the type of key provided
  > * secret - ['HS256', 'HS384', 'HS512']
  > * rsa - ['RS256', 'RS384', 'RS512']
  > * ec - ['ES256', 'ES384', 'ES512']
  > * default - ['RS256', 'RS384', 'RS512']
* `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. 
  > Eg: `"urn:foo"`, `/urn:f[o]{2}/`, `[/urn:f[o]{2}/, "urn:bar"]`
* `complete`: return an object with the decoded `{ payload, header, signature }` instead of only the usual content of the payload.
* `issuer` (optional): string or array of strings of valid values for the `iss` field.
* `jwtid` (optional): if you want to check JWT ID (`jti`), provide a string value here.
* `ignoreExpiration`: if `true` do not validate the expiration of the token.
* `ignoreNotBefore`...
* `subject`: if you want to check subject (`sub`), provide a value here
* `clockTolerance`: number of seconds to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers
* `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). 
  > 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"`).
* `clockTimestamp`: the time in seconds that should be used as the current time for all necessary comparisons.
* `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))
* `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.

```js
// verify a token symmetric - synchronous
var decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar

// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
  console.log(decoded.foo) // bar
});

// invalid token - synchronous
try {
  var decoded = jwt.verify(token, 'wrong-secret');
} catch(err) {
  // err
}

// invalid token
jwt.verify(token, 'wrong-secret', function(err, decoded) {
  // err
  // decoded undefined
});

// verify a token asymmetric
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, function(err, decoded) {
  console.log(decoded.foo) // bar
});

// verify audience
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {
  // if audience mismatch, err == invalid audience
});

// verify issuer
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {
  // if issuer mismatch, err == invalid issuer
});

// verify jwt id
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
  // if jwt id mismatch, err == invalid jwt id
});

// verify subject
var cert = fs.readFileSync('public.pem');  // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
  // if subject mismatch, err == invalid subject
});

// alg mismatch
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
  // if token alg != RS256,  err == invalid signature
});

// Verify using getKey callback
// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys.
var jwksClient = require('jwks-rsa');
var client = jwksClient({
  jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'
});
function getKey(header, callback){
  client.getSigningKey(header.kid, function(err, key) {
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

jwt.verify(token, getKey, options, function(err, decoded) {
  console.log(decoded.foo) // bar
});

```

<details>
<summary><em></em>Need to peek into a JWT without verifying it? (Click to expand)</summary>

### jwt.decode(token [, options])

(Synchronous) Returns the decoded payload without verifying if the signature is valid.

> __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.

> __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


`token` is the JsonWebToken string

`options`:

* `json`: force JSON.parse on the payload even if the header doesn't contain `"typ":"JWT"`.
* `complete`: return an object with the decoded payload and header.

Example

```js
// get the decoded payload ignoring signature, no secretOrPrivateKey needed
var decoded = jwt.decode(token);

// get the decoded payload and header
var decoded = jwt.decode(token, {complete: true});
console.log(decoded.header);
console.log(decoded.payload)
```

</details>

## Errors & Codes
Possible thrown errors during verification.
Error is the first argument of the verification callback.

### TokenExpiredError

Thrown error if the token is expired.

Error object:

* name: 'TokenExpiredError'
* message: 'jwt expired'
* expiredAt: [ExpDate]

```js
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'TokenExpiredError',
        message: 'jwt expired',
        expiredAt: 1408621000
      }
    */
  }
});
```

### JsonWebTokenError
Error object:

* name: 'JsonWebTokenError'
* message:
  * 'invalid token' - the header or payload could not be parsed
  * 'jwt malformed' - the token does not have three components (delimited by a `.`)
  * 'jwt signature is required'
  * 'invalid signature'
  * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
  * 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
  * 'jwt id invalid. expected: [OPTIONS JWT ID]'
  * 'jwt subject invalid. expected: [OPTIONS SUBJECT]'

```js
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'JsonWebTokenError',
        message: 'jwt malformed'
      }
    */
  }
});
```

### NotBeforeError
Thrown if current time is before the nbf claim.

Error object:

* name: 'NotBeforeError'
* message: 'jwt not active'
* date: 2018-10-04T16:10:44.000Z

```js
jwt.verify(token, 'shhhhh', function(err, decoded) {
  if (err) {
    /*
      err = {
        name: 'NotBeforeError',
        message: 'jwt not active',
        date: 2018-10-04T16:10:44.000Z
      }
    */
  }
});
```


## Algorithms supported

Array of supported algorithms. The following algorithms are currently supported.

| alg Parameter Value | Digital Signature or MAC Algorithm                                     |
|---------------------|------------------------------------------------------------------------|
| HS256               | HMAC using SHA-256 hash algorithm                                      |
| HS384               | HMAC using SHA-384 hash algorithm                                      |
| HS512               | HMAC using SHA-512 hash algorithm                                      |
| RS256               | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm                         |
| RS384               | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm                         |
| RS512               | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm                         |
| PS256               | RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
| PS384               | RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
| PS512               | RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0) |
| ES256               | ECDSA using P-256 curve and SHA-256 hash algorithm                     |
| ES384               | ECDSA using P-384 curve and SHA-384 hash algorithm                     |
| ES512               | ECDSA using P-521 curve and SHA-512 hash algorithm                     |
| none                | No digital signature or MAC value included                             |

## Refreshing JWTs

First of all, we recommend you to think carefully if auto-refreshing a JWT will not introduce any vulnerability in your system.

We 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.
Apart 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.

# TODO

* X.509 certificate chain is not checked

## Issue Reporting

If 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.

## Author

[Auth0](https://auth0.com)

## License

This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.


================================================
FILE: bin/changelog
================================================
#!/usr/bin/env node

var changelog = require('conventional-changelog');
var 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;

const commitPartial = ` - {{header}}

{{~!-- 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}}

{{~!-- 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}}
`;

const headerPartial = `## {{version}}{{#if title}} "{{title}}"{{/if}}{{#if date}} - {{date}}{{/if}}
`;

changelog({
  releaseCount: 19,
  // preset: 'jshint'
}, null, null, null, {
  transform: function (commit) {
    if (commit.header && semver_regex.exec(commit.header)) {
      return null;
    }
    return commit;
  },
  commitPartial: commitPartial,
  headerPartial: headerPartial
}).pipe(process.stdout);


================================================
FILE: decode.js
================================================
var jws = require('jws');

module.exports = function (jwt, options) {
  options = options || {};
  var decoded = jws.decode(jwt, options);
  if (!decoded) { return null; }
  var payload = decoded.payload;

  //try parse the payload
  if(typeof payload === 'string') {
    try {
      var obj = JSON.parse(payload);
      if(obj !== null && typeof obj === 'object') {
        payload = obj;
      }
    } catch (e) { }
  }

  //return header if `complete` option is enabled.  header includes claims
  //such as `kid` and `alg` used to select the key within a JWKS needed to
  //verify the signature
  if (options.complete === true) {
    return {
      header: decoded.header,
      payload: payload,
      signature: decoded.signature
    };
  }
  return payload;
};


================================================
FILE: index.js
================================================
module.exports = {
  decode: require('./decode'),
  verify: require('./verify'),
  sign: require('./sign'),
  JsonWebTokenError: require('./lib/JsonWebTokenError'),
  NotBeforeError: require('./lib/NotBeforeError'),
  TokenExpiredError: require('./lib/TokenExpiredError'),
};


================================================
FILE: lib/JsonWebTokenError.js
================================================
var JsonWebTokenError = function (message, error) {
  Error.call(this, message);
  if(Error.captureStackTrace) {
    Error.captureStackTrace(this, this.constructor);
  }
  this.name = 'JsonWebTokenError';
  this.message = message;
  if (error) this.inner = error;
};

JsonWebTokenError.prototype = Object.create(Error.prototype);
JsonWebTokenError.prototype.constructor = JsonWebTokenError;

module.exports = JsonWebTokenError;


================================================
FILE: lib/NotBeforeError.js
================================================
var JsonWebTokenError = require('./JsonWebTokenError');

var NotBeforeError = function (message, date) {
  JsonWebTokenError.call(this, message);
  this.name = 'NotBeforeError';
  this.date = date;
};

NotBeforeError.prototype = Object.create(JsonWebTokenError.prototype);

NotBeforeError.prototype.constructor = NotBeforeError;

module.exports = NotBeforeError;

================================================
FILE: lib/TokenExpiredError.js
================================================
var JsonWebTokenError = require('./JsonWebTokenError');

var TokenExpiredError = function (message, expiredAt) {
  JsonWebTokenError.call(this, message);
  this.name = 'TokenExpiredError';
  this.expiredAt = expiredAt;
};

TokenExpiredError.prototype = Object.create(JsonWebTokenError.prototype);

TokenExpiredError.prototype.constructor = TokenExpiredError;

module.exports = TokenExpiredError;

================================================
FILE: lib/asymmetricKeyDetailsSupported.js
================================================
const semver = require('semver');

module.exports = semver.satisfies(process.version, '>=15.7.0');


================================================
FILE: lib/psSupported.js
================================================
var semver = require('semver');

module.exports = semver.satisfies(process.version, '^6.12.0 || >=8.0.0');


================================================
FILE: lib/rsaPssKeyDetailsSupported.js
================================================
const semver = require('semver');

module.exports = semver.satisfies(process.version, '>=16.9.0');


================================================
FILE: lib/timespan.js
================================================
var ms = require('ms');

module.exports = function (time, iat) {
  var timestamp = iat || Math.floor(Date.now() / 1000);

  if (typeof time === 'string') {
    var milliseconds = ms(time);
    if (typeof milliseconds === 'undefined') {
      return;
    }
    return Math.floor(timestamp + milliseconds / 1000);
  } else if (typeof time === 'number') {
    return timestamp + time;
  } else {
    return;
  }

};

================================================
FILE: lib/validateAsymmetricKey.js
================================================
const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('./asymmetricKeyDetailsSupported');
const RSA_PSS_KEY_DETAILS_SUPPORTED = require('./rsaPssKeyDetailsSupported');

const allowedAlgorithmsForKeys = {
  'ec': ['ES256', 'ES384', 'ES512'],
  'rsa': ['RS256', 'PS256', 'RS384', 'PS384', 'RS512', 'PS512'],
  'rsa-pss': ['PS256', 'PS384', 'PS512']
};

const allowedCurves = {
  ES256: 'prime256v1',
  ES384: 'secp384r1',
  ES512: 'secp521r1',
};

module.exports = function(algorithm, key) {
  if (!algorithm || !key) return;

  const keyType = key.asymmetricKeyType;
  if (!keyType) return;

  const allowedAlgorithms = allowedAlgorithmsForKeys[keyType];

  if (!allowedAlgorithms) {
    throw new Error(`Unknown key type "${keyType}".`);
  }

  if (!allowedAlgorithms.includes(algorithm)) {
    throw new Error(`"alg" parameter for "${keyType}" key type must be one of: ${allowedAlgorithms.join(', ')}.`)
  }

  /*
   * Ignore the next block from test coverage because it gets executed
   * conditionally depending on the Node version. Not ignoring it would
   * prevent us from reaching the target % of coverage for versions of
   * Node under 15.7.0.
   */
  /* istanbul ignore next */
  if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {
    switch (keyType) {
    case 'ec':
      const keyCurve = key.asymmetricKeyDetails.namedCurve;
      const allowedCurve = allowedCurves[algorithm];

      if (keyCurve !== allowedCurve) {
        throw new Error(`"alg" parameter "${algorithm}" requires curve "${allowedCurve}".`);
      }
      break;

    case 'rsa-pss':
      if (RSA_PSS_KEY_DETAILS_SUPPORTED) {
        const length = parseInt(algorithm.slice(-3), 10);
        const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;

        if (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm) {
          throw new Error(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${algorithm}.`);
        }

        if (saltLength !== undefined && saltLength > length >> 3) {
          throw new Error(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${algorithm}.`)
        }
      }
      break;
    }
  }
}


================================================
FILE: opslevel.yml
================================================
---
version: 1
repository:
  owner: iam_protocols
  tier:
  tags:


================================================
FILE: package.json
================================================
{
  "name": "jsonwebtoken",
  "version": "9.0.3",
  "description": "JSON Web Token implementation (symmetric and asymmetric)",
  "main": "index.js",
  "nyc": {
    "check-coverage": true,
    "lines": 95,
    "statements": 95,
    "functions": 100,
    "branches": 95,
    "exclude": [
      "./test/**"
    ],
    "reporter": [
      "json",
      "lcov",
      "text-summary"
    ]
  },
  "scripts": {
    "lint": "eslint .",
    "coverage": "nyc mocha --use_strict",
    "test": "mocha",
    "prepare": "husky"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/auth0/node-jsonwebtoken"
  },
  "keywords": [
    "jwt"
  ],
  "author": "auth0",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0/node-jsonwebtoken/issues"
  },
  "dependencies": {
    "jws": "^4.0.1",
    "lodash.includes": "^4.3.0",
    "lodash.isboolean": "^3.0.3",
    "lodash.isinteger": "^4.0.4",
    "lodash.isnumber": "^3.0.3",
    "lodash.isplainobject": "^4.0.6",
    "lodash.isstring": "^4.0.1",
    "lodash.once": "^4.0.0",
    "ms": "^2.1.1",
    "semver": "^7.5.4"
  },
  "devDependencies": {
    "@commitlint/cli": "^20.3.1",
    "@commitlint/config-conventional": "^20.3.1",
    "@semantic-release/exec": "^7.0.3",
    "atob": "^2.1.2",
    "chai": "^4.1.2",
    "conventional-changelog": "~1.1.0",
    "eslint": "^4.19.1",
    "husky": "^9.1.7",
    "mocha": "^5.2.0",
    "nsp": "^2.6.2",
    "nyc": "^11.9.0",
    "semantic-release": "^25.0.2",
    "sinon": "^6.0.0"
  },
  "engines": {
    "npm": ">=6",
    "node": ">=12"
  },
  "files": [
    "lib",
    "decode.js",
    "sign.js",
    "verify.js"
  ]
}


================================================
FILE: sign.js
================================================
const timespan = require('./lib/timespan');
const PS_SUPPORTED = require('./lib/psSupported');
const validateAsymmetricKey = require('./lib/validateAsymmetricKey');
const jws = require('jws');
const includes = require('lodash.includes');
const isBoolean = require('lodash.isboolean');
const isInteger = require('lodash.isinteger');
const isNumber = require('lodash.isnumber');
const isPlainObject = require('lodash.isplainobject');
const isString = require('lodash.isstring');
const once = require('lodash.once');
const { KeyObject, createSecretKey, createPrivateKey } = require('crypto')

const SUPPORTED_ALGS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'none'];
if (PS_SUPPORTED) {
  SUPPORTED_ALGS.splice(3, 0, 'PS256', 'PS384', 'PS512');
}

const sign_options_schema = {
  expiresIn: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '"expiresIn" should be a number of seconds or string representing a timespan' },
  notBefore: { isValid: function(value) { return isInteger(value) || (isString(value) && value); }, message: '"notBefore" should be a number of seconds or string representing a timespan' },
  audience: { isValid: function(value) { return isString(value) || Array.isArray(value); }, message: '"audience" must be a string or array' },
  algorithm: { isValid: includes.bind(null, SUPPORTED_ALGS), message: '"algorithm" must be a valid string enum value' },
  header: { isValid: isPlainObject, message: '"header" must be an object' },
  encoding: { isValid: isString, message: '"encoding" must be a string' },
  issuer: { isValid: isString, message: '"issuer" must be a string' },
  subject: { isValid: isString, message: '"subject" must be a string' },
  jwtid: { isValid: isString, message: '"jwtid" must be a string' },
  noTimestamp: { isValid: isBoolean, message: '"noTimestamp" must be a boolean' },
  keyid: { isValid: isString, message: '"keyid" must be a string' },
  mutatePayload: { isValid: isBoolean, message: '"mutatePayload" must be a boolean' },
  allowInsecureKeySizes: { isValid: isBoolean, message: '"allowInsecureKeySizes" must be a boolean'},
  allowInvalidAsymmetricKeyTypes: { isValid: isBoolean, message: '"allowInvalidAsymmetricKeyTypes" must be a boolean'}
};

const registered_claims_schema = {
  iat: { isValid: isNumber, message: '"iat" should be a number of seconds' },
  exp: { isValid: isNumber, message: '"exp" should be a number of seconds' },
  nbf: { isValid: isNumber, message: '"nbf" should be a number of seconds' }
};

function validate(schema, allowUnknown, object, parameterName) {
  if (!isPlainObject(object)) {
    throw new Error('Expected "' + parameterName + '" to be a plain object.');
  }
  Object.keys(object)
    .forEach(function(key) {
      const validator = schema[key];
      if (!validator) {
        if (!allowUnknown) {
          throw new Error('"' + key + '" is not allowed in "' + parameterName + '"');
        }
        return;
      }
      if (!validator.isValid(object[key])) {
        throw new Error(validator.message);
      }
    });
}

function validateOptions(options) {
  return validate(sign_options_schema, false, options, 'options');
}

function validatePayload(payload) {
  return validate(registered_claims_schema, true, payload, 'payload');
}

const options_to_payload = {
  'audience': 'aud',
  'issuer': 'iss',
  'subject': 'sub',
  'jwtid': 'jti'
};

const options_for_objects = [
  'expiresIn',
  'notBefore',
  'noTimestamp',
  'audience',
  'issuer',
  'subject',
  'jwtid',
];

module.exports = function (payload, secretOrPrivateKey, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  } else {
    options = options || {};
  }

  const isObjectPayload = typeof payload === 'object' &&
                        !Buffer.isBuffer(payload);

  const header = Object.assign({
    alg: options.algorithm || 'HS256',
    typ: isObjectPayload ? 'JWT' : undefined,
    kid: options.keyid
  }, options.header);

  function failure(err) {
    if (callback) {
      return callback(err);
    }
    throw err;
  }

  if (!secretOrPrivateKey && options.algorithm !== 'none') {
    return failure(new Error('secretOrPrivateKey must have a value'));
  }

  if (secretOrPrivateKey != null && !(secretOrPrivateKey instanceof KeyObject)) {
    try {
      secretOrPrivateKey = createPrivateKey(secretOrPrivateKey)
    } catch (_) {
      try {
        secretOrPrivateKey = createSecretKey(typeof secretOrPrivateKey === 'string' ? Buffer.from(secretOrPrivateKey) : secretOrPrivateKey)
      } catch (_) {
        return failure(new Error('secretOrPrivateKey is not valid key material'));
      }
    }
  }

  if (header.alg.startsWith('HS') && secretOrPrivateKey.type !== 'secret') {
    return failure(new Error((`secretOrPrivateKey must be a symmetric key when using ${header.alg}`)))
  } else if (/^(?:RS|PS|ES)/.test(header.alg)) {
    if (secretOrPrivateKey.type !== 'private') {
      return failure(new Error((`secretOrPrivateKey must be an asymmetric key when using ${header.alg}`)))
    }
    if (!options.allowInsecureKeySizes &&
      !header.alg.startsWith('ES') &&
      secretOrPrivateKey.asymmetricKeyDetails !== undefined && //KeyObject.asymmetricKeyDetails is supported in Node 15+
      secretOrPrivateKey.asymmetricKeyDetails.modulusLength < 2048) {
      return failure(new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`));
    }
  }

  if (typeof payload === 'undefined') {
    return failure(new Error('payload is required'));
  } else if (isObjectPayload) {
    try {
      validatePayload(payload);
    }
    catch (error) {
      return failure(error);
    }
    if (!options.mutatePayload) {
      payload = Object.assign({},payload);
    }
  } else {
    const invalid_options = options_for_objects.filter(function (opt) {
      return typeof options[opt] !== 'undefined';
    });

    if (invalid_options.length > 0) {
      return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload'));
    }
  }

  if (typeof payload.exp !== 'undefined' && typeof options.expiresIn !== 'undefined') {
    return failure(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));
  }

  if (typeof payload.nbf !== 'undefined' && typeof options.notBefore !== 'undefined') {
    return failure(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));
  }

  try {
    validateOptions(options);
  }
  catch (error) {
    return failure(error);
  }

  if (!options.allowInvalidAsymmetricKeyTypes) {
    try {
      validateAsymmetricKey(header.alg, secretOrPrivateKey);
    } catch (error) {
      return failure(error);
    }
  }

  const timestamp = payload.iat || Math.floor(Date.now() / 1000);

  if (options.noTimestamp) {
    delete payload.iat;
  } else if (isObjectPayload) {
    payload.iat = timestamp;
  }

  if (typeof options.notBefore !== 'undefined') {
    try {
      payload.nbf = timespan(options.notBefore, timestamp);
    }
    catch (err) {
      return failure(err);
    }
    if (typeof payload.nbf === 'undefined') {
      return failure(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
    }
  }

  if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') {
    try {
      payload.exp = timespan(options.expiresIn, timestamp);
    }
    catch (err) {
      return failure(err);
    }
    if (typeof payload.exp === 'undefined') {
      return failure(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
    }
  }

  Object.keys(options_to_payload).forEach(function (key) {
    const claim = options_to_payload[key];
    if (typeof options[key] !== 'undefined') {
      if (typeof payload[claim] !== 'undefined') {
        return failure(new Error('Bad "options.' + key + '" option. The payload already has an "' + claim + '" property.'));
      }
      payload[claim] = options[key];
    }
  });

  const encoding = options.encoding || 'utf8';

  if (typeof callback === 'function') {
    callback = callback && once(callback);

    jws.createSign({
      header: header,
      privateKey: secretOrPrivateKey,
      payload: payload,
      encoding: encoding
    }).once('error', callback)
      .once('done', function (signature) {
        // TODO: Remove in favor of the modulus length check before signing once node 15+ is the minimum supported version
        if(!options.allowInsecureKeySizes && /^(?:RS|PS)/.test(header.alg) && signature.length < 256) {
          return callback(new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`))
        }
        callback(null, signature);
      });
  } else {
    let signature = jws.sign({header: header, payload: payload, secret: secretOrPrivateKey, encoding: encoding});
    // TODO: Remove in favor of the modulus length check before signing once node 15+ is the minimum supported version
    if(!options.allowInsecureKeySizes && /^(?:RS|PS)/.test(header.alg) && signature.length < 256) {
      throw new Error(`secretOrPrivateKey has a minimum key size of 2048 bits for ${header.alg}`)
    }
    return signature
  }
};


================================================
FILE: test/.eslintrc.json
================================================
{
  "env": {
    "mocha": true
  }
}


================================================
FILE: test/async_sign.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;
var jws = require('jws');
var PS_SUPPORTED = require('../lib/psSupported');
const {generateKeyPairSync} = require("crypto");

describe('signing a token asynchronously', function() {

  describe('when signing a token', function() {
    var secret = 'shhhhhh';

    it('should return the same result as singing synchronously', function(done) {
      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' }, function (err, asyncToken) {
        if (err) return done(err);
        var syncToken = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });
        expect(asyncToken).to.be.a('string');
        expect(asyncToken.split('.')).to.have.length(3);
        expect(asyncToken).to.equal(syncToken);
        done();
      });
    });

    it('should work with empty options', function (done) {
      jwt.sign({abc: 1}, "secret", {}, function (err) {
        expect(err).to.be.null;
        done();
      });
    });

    it('should work without options object at all', function (done) {
      jwt.sign({abc: 1}, "secret", function (err) {
        expect(err).to.be.null;
        done();
      });
    });

    it('should work with none algorithm where secret is set', function(done) {
      jwt.sign({ foo: 'bar' }, 'secret', { algorithm: 'none' }, function(err, token) {
        expect(token).to.be.a('string');
        expect(token.split('.')).to.have.length(3);
        done();
      });
    });

    //Known bug: https://github.com/brianloveswords/node-jws/issues/62
    //If you need this use case, you need to go for the non-callback-ish code style.
    it.skip('should work with none algorithm where secret is falsy', function(done) {
      jwt.sign({ foo: 'bar' }, undefined, { algorithm: 'none' }, function(err, token) {
        expect(token).to.be.a('string');
        expect(token.split('.')).to.have.length(3);
        done();
      });
    });

    it('should return error when secret is not a cert for RS256', function(done) {
      //this throw an error because the secret is not a cert and RS256 requires a cert.
      jwt.sign({ foo: 'bar' }, secret, { algorithm: 'RS256' }, function (err) {
        expect(err).to.be.ok;
        done();
      });
    });

    it('should not work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is false or not set', function(done) {
      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });

      jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function (err) {
        expect(err).to.be.ok;
        done();
      });
    });

    it('should work for RS algorithms when modulus length is less than 2048 when allowInsecureKeySizes is true', function(done) {
      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 1024 });

      jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256', allowInsecureKeySizes: true }, done);
    });

    if (PS_SUPPORTED) {
      it('should return error when secret is not a cert for PS256', function(done) {
        //this throw an error because the secret is not a cert and PS256 requires a cert.
        jwt.sign({ foo: 'bar' }, secret, { algorithm: 'PS256' }, function (err) {
          expect(err).to.be.ok;
          done();
        });
      });
    }

    it('should return error on wrong arguments', function(done) {
      //this throw an error because the secret is not a cert and RS256 requires a cert.
      jwt.sign({ foo: 'bar' }, secret, { notBefore: {} }, function (err) {
        expect(err).to.be.ok;
        done();
      });
    });

    it('should return error on wrong arguments (2)', function(done) {
      jwt.sign('string', 'secret', {noTimestamp: true}, function (err) {
        expect(err).to.be.ok;
        expect(err).to.be.instanceof(Error);
        done();
      });
    });

    it('should not stringify the payload', function (done) {
      jwt.sign('string', 'secret', {}, function (err, token) {
        if (err) { return done(err); }
        expect(jws.decode(token).payload).to.equal('string');
        done();
      });
    });

    describe('when mutatePayload is not set', function() {
      it('should not apply claims to the original payload object (mutatePayload defaults to false)', function(done) {
        var originalPayload = { foo: 'bar' };
        jwt.sign(originalPayload, 'secret', { notBefore: 60, expiresIn: 600 }, function (err) {
          if (err) { return done(err); }
          expect(originalPayload).to.not.have.property('nbf');
          expect(originalPayload).to.not.have.property('exp');
          done();
        });
      });
    });

    describe('when mutatePayload is set to true', function() {
      it('should apply claims directly to the original payload object', function(done) {
        var originalPayload = { foo: 'bar' };
        jwt.sign(originalPayload, 'secret', { notBefore: 60, expiresIn: 600, mutatePayload: true }, function (err) {
          if (err) { return done(err); }
          expect(originalPayload).to.have.property('nbf').that.is.a('number');
          expect(originalPayload).to.have.property('exp').that.is.a('number');
          done();
        });
      });
    });

    describe('secret must have a value', function(){
      [undefined, '', 0].forEach(function(secret){
        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) {
        // This is needed since jws will not answer for falsy secrets
          jwt.sign('string', secret, {}, function(err, token) {
            expect(err).to.exist;
            expect(err.message).to.equal('secretOrPrivateKey must have a value');
            expect(token).to.not.exist;
            done();
          });
        });
      });
    });
  });
});


================================================
FILE: test/buffer.tests.js
================================================
var jwt = require("../.");
var assert = require('chai').assert;

describe('buffer payload', function () {
  it('should work', function () {
    var payload = new Buffer('TkJyotZe8NFpgdfnmgINqg==', 'base64');
    var token = jwt.sign(payload, "signing key");
    assert.equal(jwt.decode(token), payload.toString());
  });
});


================================================
FILE: test/claim-aud.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithAudience(audience, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (audience !== undefined) {
    options.audience = audience;
  }

  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

function verifyWithAudience(token, audience,  callback) {
  testUtils.verifyJWTHelper(token, 'secret', {audience}, callback);
}

describe('audience', function() {
  describe('`jwt.sign` "audience" option validation', function () {
    [
      true,
      false,
      null,
      -1,
      1,
      0,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      {},
      {foo: 'bar'},
    ].forEach((audience) => {
      it(`should error with with value ${util.inspect(audience)}`, function (done) {
        signWithAudience(audience, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"audience" must be a string or array');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {aud: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {audience: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', '"audience" must be a string or array');
        });
      });
    });

    it('should error when "aud" is in payload', function (done) {
      signWithAudience('my_aud', {aud: ''}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.audience" option. The payload already has an "aud" property.'
          );
        });
      });
    });

    it('should error with a string payload', function (done) {
      signWithAudience('my_aud', 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid audience option for string payload');
        });
      });
    });

    it('should error with a Buffer payload', function (done) {
      signWithAudience('my_aud', new Buffer('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid audience option for object payload');
        });
      });
    });
  });

  describe('when signing and verifying a token with "audience" option', function () {
    describe('with a "aud" of "urn:foo" in payload', function () {
      let token;

      beforeEach(function (done) {
        signWithAudience('urn:foo', {}, (err, t) => {
          token = t;
          done(err);
        });
      });

      [
        undefined,
        'urn:foo',
        /^urn:f[o]{2}$/,
        ['urn:no_match', 'urn:foo'],
        ['urn:no_match', /^urn:f[o]{2}$/],
        [/^urn:no_match$/, /^urn:f[o]{2}$/],
        [/^urn:no_match$/, 'urn:foo']
      ].forEach((audience) =>{
        it(`should verify and decode with verify "audience" option of ${util.inspect(audience)}`, function (done) {
          verifyWithAudience(token, audience, (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud', 'urn:foo');
            });
          });
        });
      });

      it(`should error on no match with a string verify "audience" option`, function (done) {
        verifyWithAudience(token, 'urn:no-match', (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);
          });
        });
      });

      it('should error on no match with an array of string verify "audience" option', function (done) {
        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);
          });
        });
      });

      it('should error on no match with a Regex verify "audience" option', function (done) {
        verifyWithAudience(token, /^urn:no-match$/, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);
          });
        });
      });

      it('should error on no match with an array of Regex verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property(
              'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`
            );
          });
        });
      });

      it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property(
              'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`
            );
          });
        });
      });
    });

    describe('with an array of ["urn:foo", "urn:bar"] for "aud" value in payload', function () {
      let token;

      beforeEach(function (done) {
        signWithAudience(['urn:foo', 'urn:bar'], {}, (err, t) => {
          token = t;
          done(err);
        });
      });

      [
        undefined,
        'urn:foo',
        /^urn:f[o]{2}$/,
        ['urn:no_match', 'urn:foo'],
        ['urn:no_match', /^urn:f[o]{2}$/],
        [/^urn:no_match$/, /^urn:f[o]{2}$/],
        [/^urn:no_match$/, 'urn:foo']
      ].forEach((audience) =>{
        it(`should verify and decode with verify "audience" option of ${util.inspect(audience)}`, function (done) {
          verifyWithAudience(token, audience, (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });
      });

      it(`should error on no match with a string verify "audience" option`, function (done) {
        verifyWithAudience(token, 'urn:no-match', (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match`);
          });
        });
      });

      it('should error on no match with an array of string verify "audience" option', function (done) {
        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2`);
          });
        });
      });

      it('should error on no match with a Regex verify "audience" option', function (done) {
        verifyWithAudience(token, /^urn:no-match$/, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', `jwt audience invalid. expected: /^urn:no-match$/`);
          });
        });
      });

      it('should error on no match with an array of Regex verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property(
              'message', `jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/`
            );
          });
        });
      });

      it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property(
              'message', `jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match`
            );
          });
        });
      });

      describe('when checking for a matching on both "urn:foo" and "urn:bar"', function() {
        it('should verify with an array of stings verify "audience" option', function (done) {
          verifyWithAudience(token, ['urn:foo', 'urn:bar'], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with a Regex verify "audience" option', function (done) {
          verifyWithAudience(token, /^urn:[a-z]{3}$/, (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array of Regex verify "audience" option', function (done) {
          verifyWithAudience(token, [/^urn:f[o]{2}$/, /^urn:b[ar]{2}$/], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });
      });

      describe('when checking for a matching for "urn:foo"', function() {
        it('should verify with a string verify "audience"', function (done) {
          verifyWithAudience(token, 'urn:foo', (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with a Regex verify "audience" option', function (done) {
          verifyWithAudience(token, /^urn:f[o]{2}$/, (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array of Regex verify "audience"', function (done) {
          verifyWithAudience(token, [/^urn:no-match$/, /^urn:f[o]{2}$/], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array containing a string and a Regex verify "audience" option', function (done) {
          verifyWithAudience(token, ['urn:no_match', /^urn:f[o]{2}$/], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array containing a Regex and a string verify "audience" option', function (done) {
          verifyWithAudience(token, [/^urn:no-match$/, 'urn:foo'], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });
      });

      describe('when checking matching for "urn:bar"', function() {
        it('should verify with a string verify "audience"', function (done) {
          verifyWithAudience(token, 'urn:bar', (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with a Regex verify "audience" option', function (done) {
          verifyWithAudience(token, /^urn:b[ar]{2}$/, (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array of Regex verify "audience" option', function (done) {
          verifyWithAudience(token, [/^urn:no-match$/, /^urn:b[ar]{2}$/], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array containing a string and a Regex verify "audience" option', function (done) {
          verifyWithAudience(token, ['urn:no_match', /^urn:b[ar]{2}$/], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });

        it('should verify with an array containing a Regex and a string verify "audience" option', function (done) {
          verifyWithAudience(token, [/^urn:no-match$/, 'urn:bar'], (err, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(err).to.be.null;
              expect(decoded).to.have.property('aud').deep.equals(['urn:foo', 'urn:bar']);
            });
          });
        });
      });
    });

    describe('without a "aud" value in payload', function () {
      let token;

      beforeEach(function (done) {
        signWithAudience(undefined, {}, (err, t) => {
          token = t;
          done(err);
        });
      });

      it('should verify and decode without verify "audience" option', function (done) {
        verifyWithAudience(token, undefined, (err, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.null;
            expect(decoded).to.not.have.property('aud');
          });
        });
      });

      it('should error on no match with a string verify "audience" option', function (done) {
        verifyWithAudience(token, 'urn:no-match', (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match');
          });
        });
      });

      it('should error on no match with an array of string verify "audience" option', function (done) {
        verifyWithAudience(token, ['urn:no-match-1', 'urn:no-match-2'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'jwt audience invalid. expected: urn:no-match-1 or urn:no-match-2');
          });
        });
      });

      it('should error on no match with a Regex verify "audience" option', function (done) {
        verifyWithAudience(token, /^urn:no-match$/, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/');
          });
        });
      });

      it('should error on no match with an array of Regex verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match-1$/, /^urn:no-match-2$/], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match-1$/ or /^urn:no-match-2$/');
          });
        });
      });

      it('should error on no match with an array of a Regex and a string in verify "audience" option', function (done) {
        verifyWithAudience(token, [/^urn:no-match$/, 'urn:no-match'], (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'jwt audience invalid. expected: /^urn:no-match$/ or urn:no-match');
          });
        });
      });
    });
  });
});


================================================
FILE: test/claim-exp.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const sinon = require('sinon');
const util = require('util');
const testUtils = require('./test-utils');
const jws = require('jws');

function signWithExpiresIn(expiresIn, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (expiresIn !== undefined) {
    options.expiresIn = expiresIn;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('expires', function() {
  describe('`jwt.sign` "expiresIn" option validation', function () {
    [
      true,
      false,
      null,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      ' ',
      '',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((expiresIn) => {
      it(`should error with with value ${util.inspect(expiresIn)}`, function (done) {
        signWithExpiresIn(expiresIn, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message')
              .match(/"expiresIn" should be a number of seconds or string representing a timespan/);
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {expiresIn: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {expiresIn: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            '"expiresIn" should be a number of seconds or string representing a timespan'
          );
        });
      });
    });

    it ('should error when "exp" is in payload', function(done) {
      signWithExpiresIn(100, {exp: 100}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.expiresIn" option the payload already has an "exp" property.'
          );
        });
      });
    });

    it('should error with a string payload', function(done) {
      signWithExpiresIn(100, 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid expiresIn option for string payload');
        });
      });
    });

    it('should error with a Buffer payload', function(done) {
      signWithExpiresIn(100, Buffer.from('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid expiresIn option for object payload');
        });
      });
    });
  });

  describe('`jwt.sign` "exp" claim validation', function () {
    [
      true,
      false,
      null,
      undefined,
      '',
      ' ',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((exp) => {
      it(`should error with with value ${util.inspect(exp)}`, function (done) {
        signWithExpiresIn(undefined, {exp}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"exp" should be a number of seconds');
          });
        });
      });
    });
  });

  describe('"exp" in payload validation', function () {
    [
      true,
      false,
      null,
      -Infinity,
      Infinity,
      NaN,
      '',
      ' ',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((exp) => {
      it(`should error with with value ${util.inspect(exp)}`, function (done) {
        const header = { alg: 'HS256' };
        const payload = { exp };
        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });
        testUtils.verifyJWTHelper(token, 'secret', { exp }, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'invalid exp value');
          });
        });
      });
    })
  });

  describe('when signing and verifying a token with expires option', function () {
    let fakeClock;
    beforeEach(function() {
      fakeClock = sinon.useFakeTimers({now: 60000});
    });

    afterEach(function() {
      fakeClock.uninstall();
    });

    it('should set correct "exp" with negative number of seconds', function(done) {
      signWithExpiresIn(-10, {}, (e1, token) => {
        fakeClock.tick(-10001);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 50);
          });
        })
      });
    });

    it('should set correct "exp" with positive number of seconds', function(done) {
      signWithExpiresIn(10, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 70);
          });
        })
      });
    });

    it('should set correct "exp" with zero seconds', function(done) {
      signWithExpiresIn(0, {}, (e1, token) => {
        fakeClock.tick(-1);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 60);
          });
        })
      });
    });

    it('should set correct "exp" with negative string timespan', function(done) {
      signWithExpiresIn('-10 s', {}, (e1, token) => {
        fakeClock.tick(-10001);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 50);
          });
        })
      });
    });

    it('should set correct "exp" with positive string timespan', function(done) {
      signWithExpiresIn('10 s', {}, (e1, token) => {
        fakeClock.tick(-10001);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 70);
          });
        })
      });
    });

    it('should set correct "exp" with zero string timespan', function(done) {
      signWithExpiresIn('0 s', {}, (e1, token) => {
        fakeClock.tick(-1);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 60);
          });
        })
      });
    });

    // TODO an exp of -Infinity should fail validation
    it('should set null "exp" when given -Infinity', function (done) {
      signWithExpiresIn(undefined, {exp: -Infinity}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('exp', null);
        });
      });
    });

    // TODO an exp of Infinity should fail validation
    it('should set null "exp" when given value Infinity', function (done) {
      signWithExpiresIn(undefined, {exp: Infinity}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('exp', null);
        });
      });
    });

    // TODO an exp of NaN should fail validation
    it('should set null "exp" when given value NaN', function (done) {
      signWithExpiresIn(undefined, {exp: NaN}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('exp', null);
        });
      });
    });

    it('should set correct "exp" when "iat" is passed', function (done) {
      signWithExpiresIn(-10, {iat: 80}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('exp', 70);
          });
        })
      });
    });

    it('should verify "exp" using "clockTimestamp"', function (done) {
      signWithExpiresIn(10, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 69}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('exp', 70);
          });
        })
      });
    });

    it('should verify "exp" using "clockTolerance"', function (done) {
      signWithExpiresIn(5, {}, (e1, token) => {
        fakeClock.tick(10000);
        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 6}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('exp', 65);
          });
        })
      });
    });

    it('should ignore a expired token when "ignoreExpiration" is true', function (done) {
      signWithExpiresIn('-10 s', {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {ignoreExpiration: true}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('exp', 50);
          });
        })
      });
    });

    it('should error on verify if "exp" is at current time', function(done) {
      signWithExpiresIn(undefined, {exp: 60}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.TokenExpiredError);
            expect(e2).to.have.property('message', 'jwt expired');
          });
        });
      });
    });

    it('should error on verify if "exp" is before current time using clockTolerance', function (done) {
      signWithExpiresIn(-5, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 5}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.TokenExpiredError);
            expect(e2).to.have.property('message', 'jwt expired');
          });
        });
      });
    });
  });
});


================================================
FILE: test/claim-iat.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const sinon = require('sinon');
const util = require('util');
const testUtils = require('./test-utils');
const jws = require('jws');

function signWithIssueAt(issueAt, options, callback) {
  const payload = {};
  if (issueAt !== undefined) {
    payload.iat = issueAt;
  }
  const opts = Object.assign({algorithm: 'HS256'}, options);
  // async calls require a truthy secret
  // see: https://github.com/brianloveswords/node-jws/issues/62
  testUtils.signJWTHelper(payload, 'secret', opts, callback);
}

function verifyWithIssueAt(token, maxAge, options, secret, callback) {
  const opts = Object.assign({maxAge}, options);
  testUtils.verifyJWTHelper(token, secret, opts, callback);
}

describe('issue at', function() {
  describe('`jwt.sign` "iat" claim validation', function () {
    [
      true,
      false,
      null,
      '',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((iat) => {
      it(`should error with iat of ${util.inspect(iat)}`, function (done) {
        signWithIssueAt(iat, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err.message).to.equal('"iat" should be a number of seconds');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {iat: undefined}
    it('should error with iat of undefined', function (done) {
      testUtils.signJWTHelper({iat: undefined}, 'secret', {algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err.message).to.equal('"iat" should be a number of seconds');
        });
      });
    });
  });

  describe('"iat" in payload with "maxAge" option validation', function () {
    [
      true,
      false,
      null,
      undefined,
      -Infinity,
      Infinity,
      NaN,
      '',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((iat) => {
      it(`should error with iat of ${util.inspect(iat)}`, function (done) {
        const header = { alg: 'HS256' };
        const payload = { iat };
        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });
        verifyWithIssueAt(token, '1 min', {}, 'secret', (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err.message).to.equal('iat required when maxAge is specified');
          });
        });
      });
    })
  });

  describe('when signing a token', function () {
    let fakeClock;
    beforeEach(function () {
      fakeClock = sinon.useFakeTimers({now: 60000});
    });

    afterEach(function () {
      fakeClock.uninstall();
    });

    [
      {
        description: 'should default to current time for "iat"',
        iat: undefined,
        expectedIssueAt: 60,
        options: {}
      },
      {
        description: 'should sign with provided time for "iat"',
        iat: 100,
        expectedIssueAt: 100,
        options: {}
      },
      // TODO an iat of -Infinity should fail validation
      {
        description: 'should set null "iat" when given -Infinity',
        iat: -Infinity,
        expectedIssueAt: null,
        options: {}
      },
      // TODO an iat of Infinity should fail validation
      {
        description: 'should set null "iat" when given Infinity',
        iat: Infinity,
        expectedIssueAt: null,
        options: {}
      },
      // TODO an iat of NaN should fail validation
      {
        description: 'should set to current time for "iat" when given value NaN',
        iat: NaN,
        expectedIssueAt: 60,
        options: {}
      },
      {
        description: 'should remove default "iat" with "noTimestamp" option',
        iat: undefined,
        expectedIssueAt: undefined,
        options: {noTimestamp: true}
      },
      {
        description: 'should remove provided "iat" with "noTimestamp" option',
        iat: 10,
        expectedIssueAt: undefined,
        options: {noTimestamp: true}
      },
    ].forEach((testCase) => {
      it(testCase.description, function (done) {
        signWithIssueAt(testCase.iat, testCase.options, (err, token) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.null;
            expect(jwt.decode(token).iat).to.equal(testCase.expectedIssueAt);
          });
        });
      });
    });
  });

  describe('when verifying a token', function() {
    let fakeClock;

    beforeEach(function() {
      fakeClock = sinon.useFakeTimers({now: 60000});
    });

    afterEach(function () {
      fakeClock.uninstall();
    });

    [
      {
        description: 'should verify using "iat" before the "maxAge"',
        clockAdvance: 10000,
        maxAge: 11,
        options: {},
      },
      {
        description: 'should verify using "iat" before the "maxAge" with a provided "clockTimestamp',
        clockAdvance: 60000,
        maxAge: 11,
        options: {clockTimestamp: 70},
      },
      {
        description: 'should verify using "iat" after the "maxAge" but within "clockTolerance"',
        clockAdvance: 10000,
        maxAge: 9,
        options: {clockTimestamp: 2},
      },
    ].forEach((testCase) => {
      it(testCase.description, function (done) {
        const token = jwt.sign({}, 'secret', {algorithm: 'HS256'});
        fakeClock.tick(testCase.clockAdvance);
        verifyWithIssueAt(token, testCase.maxAge, testCase.options, 'secret', (err, token) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.null;
            expect(token).to.be.a('object');
          });
        });
      });
    });

    [
      {
        description: 'should throw using "iat" equal to the "maxAge"',
        clockAdvance: 10000,
        maxAge: 10,
        options: {},
        expectedError: 'maxAge exceeded',
        expectedExpiresAt: 70000,
      },
      {
        description: 'should throw using "iat" after the "maxAge"',
        clockAdvance: 10000,
        maxAge: 9,
        options: {},
        expectedError: 'maxAge exceeded',
        expectedExpiresAt: 69000,
      },
      {
        description: 'should throw using "iat" after the "maxAge" with a provided "clockTimestamp',
        clockAdvance: 60000,
        maxAge: 10,
        options: {clockTimestamp: 70},
        expectedError: 'maxAge exceeded',
        expectedExpiresAt: 70000,
      },
      {
        description: 'should throw using "iat" after the "maxAge" and "clockTolerance',
        clockAdvance: 10000,
        maxAge: 8,
        options: {clockTolerance: 2},
        expectedError: 'maxAge exceeded',
        expectedExpiresAt: 68000,
      },
    ].forEach((testCase) => {
      it(testCase.description, function(done) {
        const expectedExpiresAtDate = new Date(testCase.expectedExpiresAt);
        const token = jwt.sign({}, 'secret', {algorithm: 'HS256'});
        fakeClock.tick(testCase.clockAdvance);

        verifyWithIssueAt(token, testCase.maxAge, testCase.options, 'secret', (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err.message).to.equal(testCase.expectedError);
            expect(err.expiredAt).to.deep.equal(expectedExpiresAtDate);
          });
        });
      });
    });
  });

  describe('with string payload', function () {
    it('should not add iat to string', function (done) {
      const payload = 'string payload';
      const options = {algorithm: 'HS256'};
      testUtils.signJWTHelper(payload, 'secret', options, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.equal(payload);
        });
      });
    });

    it('should not add iat to stringified object', function (done) {
      const payload = '{}';
      const options = {algorithm: 'HS256', header: {typ: 'JWT'}};
      testUtils.signJWTHelper(payload, 'secret', options, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.equal(null);
          expect(JSON.stringify(decoded)).to.equal(payload);
        });
      });
    });
  });
});


================================================
FILE: test/claim-iss.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithIssuer(issuer, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (issuer !== undefined) {
    options.issuer = issuer;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('issuer', function() {
  describe('`jwt.sign` "issuer" option validation', function () {
    [
      true,
      false,
      null,
      -1,
      0,
      1,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((issuer) => {
      it(`should error with with value ${util.inspect(issuer)}`, function (done) {
        signWithIssuer(issuer, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"issuer" must be a string');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {issuer: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {issuer: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', '"issuer" must be a string');
        });
      });
    });

    it('should error when "iss" is in payload', function (done) {
      signWithIssuer('foo', {iss: 'bar'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.issuer" option. The payload already has an "iss" property.'
          );
        });
      });
    });

    it('should error with a string payload', function (done) {
      signWithIssuer('foo', 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid issuer option for string payload'
          );
        });
      });
    });

    it('should error with a Buffer payload', function (done) {
      signWithIssuer('foo', new Buffer('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid issuer option for object payload'
          );
        });
      });
    });
  });

  describe('when signing and verifying a token', function () {
    it('should not verify "iss" if verify "issuer" option not provided', function(done) {
      signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iss', 'foo');
          });
        })
      });
    });

    describe('with string "issuer" option', function () {
      it('should verify with a string "issuer"', function (done) {
        signWithIssuer('foo', {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('iss', 'foo');
            });
          })
        });
      });

      it('should verify with a string "iss"', function (done) {
        signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('iss', 'foo');
            });
          })
        });
      });

      it('should error if "iss" does not match verify "issuer" option', function(done) {
        signWithIssuer(undefined, {iss: 'foobar'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo');
            });
          })
        });
      });

      it('should error without "iss" and with verify "issuer" option', function(done) {
        signWithIssuer(undefined, {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: 'foo'}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo');
            });
          })
        });
      });
    });

    describe('with array "issuer" option', function () {
      it('should verify with a string "issuer"', function (done) {
        signWithIssuer('bar', {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('iss', 'bar');
            });
          })
        });
      });

      it('should verify with a string "iss"', function (done) {
        signWithIssuer(undefined, {iss: 'foo'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('iss', 'foo');
            });
          })
        });
      });

      it('should error if "iss" does not match verify "issuer" option', function(done) {
        signWithIssuer(undefined, {iss: 'foobar'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo,bar');
            });
          })
        });
      });

      it('should error without "iss" and with verify "issuer" option', function(done) {
        signWithIssuer(undefined, {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {issuer: ['foo', 'bar']}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt issuer invalid. expected: foo,bar');
            });
          })
        });
      });
    });
  });
});


================================================
FILE: test/claim-jti.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithJWTId(jwtid, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (jwtid !== undefined) {
    options.jwtid = jwtid;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('jwtid', function() {
  describe('`jwt.sign` "jwtid" option validation', function () {
    [
      true,
      false,
      null,
      -1,
      0,
      1,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((jwtid) => {
      it(`should error with with value ${util.inspect(jwtid)}`, function (done) {
        signWithJWTId(jwtid, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"jwtid" must be a string');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {jwtid: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {jwtid: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', '"jwtid" must be a string');
        });
      });
    });

    it('should error when "jti" is in payload', function (done) {
      signWithJWTId('foo', {jti: 'bar'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.jwtid" option. The payload already has an "jti" property.'
          );
        });
      });
    });

    it('should error with a string payload', function (done) {
      signWithJWTId('foo', 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid jwtid option for string payload'
          );
        });
      });
    });

    it('should error with a Buffer payload', function (done) {
      signWithJWTId('foo', new Buffer('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid jwtid option for object payload'
          );
        });
      });
    });
  });

  describe('when signing and verifying a token', function () {
    it('should not verify "jti" if verify "jwtid" option not provided', function(done) {
      signWithJWTId(undefined, {jti: 'foo'}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('jti', 'foo');
          });
        })
      });
    });

    describe('with "jwtid" option', function () {
      it('should verify with "jwtid" option', function (done) {
        signWithJWTId('foo', {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('jti', 'foo');
            });
          })
        });
      });

      it('should verify with "jti" in payload', function (done) {
        signWithJWTId(undefined, {jti: 'foo'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {jetid: 'foo'}, (e2, decoded) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.null;
              expect(decoded).to.have.property('jti', 'foo');
            });
          })
        });
      });

      it('should error if "jti" does not match verify "jwtid" option', function(done) {
        signWithJWTId(undefined, {jti: 'bar'}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt jwtid invalid. expected: foo');
            });
          })
        });
      });

      it('should error without "jti" and with verify "jwtid" option', function(done) {
        signWithJWTId(undefined, {}, (e1, token) => {
          testUtils.verifyJWTHelper(token, 'secret', {jwtid: 'foo'}, (e2) => {
            testUtils.asyncCheck(done, () => {
              expect(e1).to.be.null;
              expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
              expect(e2).to.have.property('message', 'jwt jwtid invalid. expected: foo');
            });
          })
        });
      });
    });
  });
});


================================================
FILE: test/claim-nbf.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const sinon = require('sinon');
const util = require('util');
const testUtils = require('./test-utils');
const jws = require('jws');

function signWithNotBefore(notBefore, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (notBefore !== undefined) {
    options.notBefore = notBefore;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('not before', function() {
  describe('`jwt.sign` "notBefore" option validation', function () {
    [
      true,
      false,
      null,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      '',
      ' ',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((notBefore) => {
      it(`should error with with value ${util.inspect(notBefore)}`, function (done) {
        signWithNotBefore(notBefore, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message')
              .match(/"notBefore" should be a number of seconds or string representing a timespan/);
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {notBefore: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {notBefore: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            '"notBefore" should be a number of seconds or string representing a timespan'
          );
        });
      });
    });

    it('should error when "nbf" is in payload', function (done) {
      signWithNotBefore(100, {nbf: 100}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.notBefore" option the payload already has an "nbf" property.'
          );
        });
      });
    });

    it('should error with a string payload', function (done) {
      signWithNotBefore(100, 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid notBefore option for string payload');
        });
      });
    });

    it('should error with a Buffer payload', function (done) {
      signWithNotBefore(100, new Buffer('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', 'invalid notBefore option for object payload');
        });
      });
    });
  });

  describe('`jwt.sign` "nbf" claim validation', function () {
    [
      true,
      false,
      null,
      undefined,
      '',
      ' ',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((nbf) => {
      it(`should error with with value ${util.inspect(nbf)}`, function (done) {
        signWithNotBefore(undefined, {nbf}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"nbf" should be a number of seconds');
          });
        });
      });
    });
  });

  describe('"nbf" in payload validation', function () {
    [
      true,
      false,
      null,
      -Infinity,
      Infinity,
      NaN,
      '',
      ' ',
      'invalid',
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((nbf) => {
      it(`should error with with value ${util.inspect(nbf)}`, function (done) {
        const header = { alg: 'HS256' };
        const payload = { nbf };
        const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });
        testUtils.verifyJWTHelper(token, 'secret', {nbf}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(err).to.have.property('message', 'invalid nbf value');
          });
        });
      });
    })
  });

  describe('when signing and verifying a token with "notBefore" option', function () {
    let fakeClock;
    beforeEach(function () {
      fakeClock = sinon.useFakeTimers({now: 60000});
    });

    afterEach(function () {
      fakeClock.uninstall();
    });

    it('should set correct "nbf" with negative number of seconds', function (done) {
      signWithNotBefore(-10, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 50);
          });
        })
      });
    });

    it('should set correct "nbf" with positive number of seconds', function (done) {
      signWithNotBefore(10, {}, (e1, token) => {
        fakeClock.tick(10000);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 70);
          });
        })
      });
    });

    it('should set correct "nbf" with zero seconds', function (done) {
      signWithNotBefore(0, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 60);
          });
        })
      });
    });

    it('should set correct "nbf" with negative string timespan', function (done) {
      signWithNotBefore('-10 s', {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 50);
          });
        })
      });
    });

    it('should set correct "nbf" with positive string timespan', function (done) {
      signWithNotBefore('10 s', {}, (e1, token) => {
        fakeClock.tick(10000);
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 70);
          });
        })
      });
    });

    it('should set correct "nbf" with zero string timespan', function (done) {
      signWithNotBefore('0 s', {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 60);
          });
        })
      });
    });

    // TODO an nbf of -Infinity should fail validation
    it('should set null "nbf" when given -Infinity', function (done) {
      signWithNotBefore(undefined, {nbf: -Infinity}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('nbf', null);
        });
      });
    });

    // TODO an nbf of Infinity should fail validation
    it('should set null "nbf" when given value Infinity', function (done) {
      signWithNotBefore(undefined, {nbf: Infinity}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('nbf', null);
        });
      });
    });

    // TODO an nbf of NaN should fail validation
    it('should set null "nbf" when given value NaN', function (done) {
      signWithNotBefore(undefined, {nbf: NaN}, (err, token) => {
        const decoded = jwt.decode(token);
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.null;
          expect(decoded).to.have.property('nbf', null);
        });
      });
    });

    it('should set correct "nbf" when "iat" is passed', function (done) {
      signWithNotBefore(-10, {iat: 40}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('nbf', 30);
          });
        })
      });
    });

    it('should verify "nbf" using "clockTimestamp"', function (done) {
      signWithNotBefore(10, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {clockTimestamp: 70}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('nbf', 70);
          });
        })
      });
    });

    it('should verify "nbf" using "clockTolerance"', function (done) {
      signWithNotBefore(5, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 6}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('nbf', 65);
          });
        })
      });
    });

    it('should ignore a not active token when "ignoreNotBefore" is true', function (done) {
      signWithNotBefore('10 s', {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {ignoreNotBefore: true}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('iat', 60);
            expect(decoded).to.have.property('nbf', 70);
          });
        })
      });
    });

    it('should error on verify if "nbf" is after current time', function (done) {
      signWithNotBefore(undefined, {nbf: 61}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.NotBeforeError);
            expect(e2).to.have.property('message', 'jwt not active');
          });
        })
      });
    });

    it('should error on verify if "nbf" is after current time using clockTolerance', function (done) {
      signWithNotBefore(5, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {clockTolerance: 4}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.NotBeforeError);
            expect(e2).to.have.property('message', 'jwt not active');
          });
        })
      });
    });
  });
});


================================================
FILE: test/claim-private.tests.js
================================================
'use strict';

const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithPayload(payload, callback) {
  testUtils.signJWTHelper(payload, 'secret', {algorithm: 'HS256'}, callback);
}

describe('with a private claim', function() {
  [
    true,
    false,
    null,
    -1,
    0,
    1,
    -1.1,
    1.1,
    '',
    'private claim',
    'UTF8 - José',
    [],
    ['foo'],
    {},
    {foo: 'bar'},
  ].forEach((privateClaim) => {
    it(`should sign and verify with claim of ${util.inspect(privateClaim)}`, function (done) {
      signWithPayload({privateClaim}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('privateClaim').to.deep.equal(privateClaim);
          });
        })
      });
    });
  });

  // these values JSON.stringify to null
  [
    -Infinity,
    Infinity,
    NaN,
  ].forEach((privateClaim) => {
    it(`should sign and verify with claim of ${util.inspect(privateClaim)}`, function (done) {
      signWithPayload({privateClaim}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('privateClaim', null);
          });
        })
      });
    });
  });

  // private claims with value undefined are not added to the payload
  it(`should sign and verify with claim of undefined`, function (done) {
    signWithPayload({privateClaim: undefined}, (e1, token) => {
      testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
        testUtils.asyncCheck(done, () => {
          expect(e1).to.be.null;
          expect(e2).to.be.null;
          expect(decoded).to.not.have.property('privateClaim');
        });
      })
    });
  });
});


================================================
FILE: test/claim-sub.tests.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithSubject(subject, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (subject !== undefined) {
    options.subject = subject;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('subject', function() {
  describe('`jwt.sign` "subject" option validation', function () {
    [
      true,
      false,
      null,
      -1,
      0,
      1,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((subject) => {
      it(`should error with with value ${util.inspect(subject)}`, function (done) {
        signWithSubject(subject, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"subject" must be a string');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {subject: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {subject: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', '"subject" must be a string');
        });
      });
    });

    it('should error when "sub" is in payload', function (done) {
      signWithSubject('foo', {sub: 'bar'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'Bad "options.subject" option. The payload already has an "sub" property.'
          );
        });
      });
    });

    it('should error with a string payload', function (done) {
      signWithSubject('foo', 'a string payload', (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid subject option for string payload'
          );
        });
      });
    });

    it('should error with a Buffer payload', function (done) {
      signWithSubject('foo', new Buffer('a Buffer payload'), (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property(
            'message',
            'invalid subject option for object payload'
          );
        });
      });
    });
  });

  describe('when signing and verifying a token with "subject" option', function () {
    it('should verify with a string "subject"', function (done) {
      signWithSubject('foo', {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('sub', 'foo');
          });
        })
      });
    });

    it('should verify with a string "sub"', function (done) {
      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('sub', 'foo');
          });
        })
      });
    });

    it('should not verify "sub" if verify "subject" option not provided', function(done) {
      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {}, (e2, decoded) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.null;
            expect(decoded).to.have.property('sub', 'foo');
          });
        })
      });
    });

    it('should error if "sub" does not match verify "subject" option', function(done) {
      signWithSubject(undefined, {sub: 'foo'}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {subject: 'bar'}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(e2).to.have.property('message', 'jwt subject invalid. expected: bar');
          });
        })
      });
    });

    it('should error without "sub" and with verify "subject" option', function(done) {
      signWithSubject(undefined, {}, (e1, token) => {
        testUtils.verifyJWTHelper(token, 'secret', {subject: 'foo'}, (e2) => {
          testUtils.asyncCheck(done, () => {
            expect(e1).to.be.null;
            expect(e2).to.be.instanceOf(jwt.JsonWebTokenError);
            expect(e2).to.have.property('message', 'jwt subject invalid. expected: foo');
          });
        })
      });
    });
  });
});


================================================
FILE: test/decoding.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('decoding', function() {

  it('should not crash when decoding a null token', function () {
    var decoded = jwt.decode("null");
    expect(decoded).to.equal(null);
  });

});


================================================
FILE: test/dsa-private.pem
================================================
-----BEGIN DSA PRIVATE KEY-----
MIIGWAIBAAKCAgEArzbPbt//BQpsYsnoZR4R9nXgcuvcXoH8WZjRsb4ZPfVJGchG
7CfRMlG0HR34vcUpehNj5pAavErhfNnk1CEal0TyDsOkBY/+JG239zXgRzMYjSE6
ptX5kj5pGv0uXVoozSP/JZblI8/Spd6TZkblLNAYOl3ssfcUGN4NFDXlzmiWvP+q
6ZUgE8tD7CSryicICKmXcVQIa6AG8ultYa6mBAaewzMbiIt2TUo9smglpEqGeHoL
CuLb3e7zLf0AhWDZOgTTfe1KFEiK6TXMe9HWYeP3MPuyKhS20GmT/Zcu5VN4wbr0
bP+mTWk700oLJ0OPQ6YgGkyqBmh/Bsi/TqnpJWS/mjRbJEe3E2NmNMwmP4jwJ79V
JClp5Gg9kbM6hPkmGNnhbbFzn3kwY3pi9/AiqpGyr3GUPhXvP7fYwAu/A5ISKw8r
87j/EJntyIzm51fcm8Q0mq1IDt4tNkIOwJEIc45h9r7ZC1VAKkzlCa7XT04GguFo
JMaJBYESYcOAmbKRojo8P/cN4fPuemuhQFQplkFIM6FtG9cJMo2ayp6ukH9Up8tn
8j7YgE/m9BL9SnUIbNlti9j0cNgeKVn24WC38hw9D8M0/sR5gYyclWh/OotCttoQ
I8ySZzSvB4GARZHbexagvg1EdV93ctYyAWGLkpJYAzuiXbt7FayG7e2ifYkCIQDp
IldsAFGVaiJRQdiKsWdReOSjzH6h8cw6Co3OCISiOQKCAgEAnSU29U65jK3W2BiA
fKTlTBx2yDUCDFeqnla5arZ2njGsUKiP2nocArAPLQggwk9rfqufybQltM8+zjmE
zeb4mUCVhSbTH7BvP903U0YEabZJCHLx80nTywq2RgQs0Qmn43vs2U5EidYR0xj8
CCNAH5gdzd9/CL1RYACHAf7zj4n68ZaNkAy9Jz1JjYXjP6IAxJh1W/Y0vsdFdIJ/
dnuxsyMCUCSwDvSNApSfATO/tw+DCVpGgKo4qE8b8lsfXKeihuMzyXuSe/D98YN2
UFWRTQ6gFxGrntg3LOn41RXSkXxzixgl7quacIJzm8jrFkDJSx4AZ8rgt/9JbThA
XF9PVlCVv7GL1NztUs4cDK+zsJld4O1rlI3QOz5DWq9oA+Hj1MN3L9IW3Iv2Offo
AaubXJhuv0xPWYmtCo06mPgSwkWPjDnGCbp1vuI8zPTsfyhsahuKeW0h8JttW4GB
6CTtC1AVWA1pJug5pBo36S5G24ihRsdG3Q5/aTlnke7t7H1Tkh2KuvV9hD5a5Xtw
cnuiEcKjyR0FWR81RdsAKh+7QNI3Lx75c95i22Aupon5R/Qkb05VzHdd299bb78c
x5mW8Dsg4tKLF7kpDAcWmx7JpkPHQ+5V9N766sfZ+z/PiVWfNAK8gzJRn/ceLQcK
C6uOhcZgN0o4UYrmYEy9icxJ44wCggIBAIu+yagyVMS+C5OqOprmtteh/+MyaYI+
Q3oPXFR8eHLJftsBWev1kRfje1fdxzzx/k4SQMRbxxbMtGV74KNwRUzEWOkoyAHP
AAjhMio1mxknPwAxRjWDOSE0drGJPyGpI9ZfpMUtvekQO7MCGqa45vPldY10RwZC
VN66AIpxSF0MG1OEmgD+noHMI7moclw/nw+ZUPaIFxvPstlD4EsPDkdE0I6x3k3b
UXlWAYAJFR6fNf8+Ki3xnjLjW9da3cU/p2H7+LrFDP+kPUGJpqr4bG606GUcV3Cl
dznoqlgaudWgcQCQx0NPzi7k5O7PXr7C3UU0cg+5+GkviIzogaioxidvvchnG+UU
0y5nVuji6G69j5sUhlcFXte31Nte2VUb6P8umo+mbDT0UkZZZzoOsCpw+cJ8OHOV
emFIhVphNHqQt20Tq6WVRBx+p4+YNWiThvmLtmLh0QghdnUrJZxyXx7/p8K5SE9/
+qU11t5dUvYS+53U1gJ2kgIFO4Zt6gaoOyexTt5f4Ganh9IcJ01wegl5WT58aDtf
hmw0HnOrgbWt4lRkxOra281hL74xcgtgMZQ32PTOy8wTEVTk03mmqlIq/dV4jgBc
Nh1FGQwGEeGlfbuNSB4nqgMN6zn1PmI7oCWLD9XLR6VZTebF7pGfpHtYczyivuxf
e1YOro6e0mUqAiEAx4K3cPG3dxH91uU3L+sS2vzqXEVn2BmSMmkGczSOgn4=
-----END DSA PRIVATE KEY-----


================================================
FILE: test/dsa-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MIIGSDCCBDoGByqGSM44BAEwggQtAoICAQCvNs9u3/8FCmxiyehlHhH2deBy69xe
gfxZmNGxvhk99UkZyEbsJ9EyUbQdHfi9xSl6E2PmkBq8SuF82eTUIRqXRPIOw6QF
j/4kbbf3NeBHMxiNITqm1fmSPmka/S5dWijNI/8lluUjz9Kl3pNmRuUs0Bg6Xeyx
9xQY3g0UNeXOaJa8/6rplSATy0PsJKvKJwgIqZdxVAhroAby6W1hrqYEBp7DMxuI
i3ZNSj2yaCWkSoZ4egsK4tvd7vMt/QCFYNk6BNN97UoUSIrpNcx70dZh4/cw+7Iq
FLbQaZP9ly7lU3jBuvRs/6ZNaTvTSgsnQ49DpiAaTKoGaH8GyL9OqeklZL+aNFsk
R7cTY2Y0zCY/iPAnv1UkKWnkaD2RszqE+SYY2eFtsXOfeTBjemL38CKqkbKvcZQ+
Fe8/t9jAC78DkhIrDyvzuP8Qme3IjObnV9ybxDSarUgO3i02Qg7AkQhzjmH2vtkL
VUAqTOUJrtdPTgaC4WgkxokFgRJhw4CZspGiOjw/9w3h8+56a6FAVCmWQUgzoW0b
1wkyjZrKnq6Qf1Sny2fyPtiAT+b0Ev1KdQhs2W2L2PRw2B4pWfbhYLfyHD0PwzT+
xHmBjJyVaH86i0K22hAjzJJnNK8HgYBFkdt7FqC+DUR1X3dy1jIBYYuSklgDO6Jd
u3sVrIbt7aJ9iQIhAOkiV2wAUZVqIlFB2IqxZ1F45KPMfqHxzDoKjc4IhKI5AoIC
AQCdJTb1TrmMrdbYGIB8pOVMHHbINQIMV6qeVrlqtnaeMaxQqI/aehwCsA8tCCDC
T2t+q5/JtCW0zz7OOYTN5viZQJWFJtMfsG8/3TdTRgRptkkIcvHzSdPLCrZGBCzR
Cafje+zZTkSJ1hHTGPwII0AfmB3N338IvVFgAIcB/vOPifrxlo2QDL0nPUmNheM/
ogDEmHVb9jS+x0V0gn92e7GzIwJQJLAO9I0ClJ8BM7+3D4MJWkaAqjioTxvyWx9c
p6KG4zPJe5J78P3xg3ZQVZFNDqAXEaue2Dcs6fjVFdKRfHOLGCXuq5pwgnObyOsW
QMlLHgBnyuC3/0ltOEBcX09WUJW/sYvU3O1SzhwMr7OwmV3g7WuUjdA7PkNar2gD
4ePUw3cv0hbci/Y59+gBq5tcmG6/TE9Zia0KjTqY+BLCRY+MOcYJunW+4jzM9Ox/
KGxqG4p5bSHwm21bgYHoJO0LUBVYDWkm6DmkGjfpLkbbiKFGx0bdDn9pOWeR7u3s
fVOSHYq69X2EPlrle3Bye6IRwqPJHQVZHzVF2wAqH7tA0jcvHvlz3mLbYC6miflH
9CRvTlXMd13b31tvvxzHmZbwOyDi0osXuSkMBxabHsmmQ8dD7lX03vrqx9n7P8+J
VZ80AryDMlGf9x4tBwoLq46FxmA3SjhRiuZgTL2JzEnjjAOCAgYAAoICAQCLvsmo
MlTEvguTqjqa5rbXof/jMmmCPkN6D1xUfHhyyX7bAVnr9ZEX43tX3cc88f5OEkDE
W8cWzLRle+CjcEVMxFjpKMgBzwAI4TIqNZsZJz8AMUY1gzkhNHaxiT8hqSPWX6TF
Lb3pEDuzAhqmuObz5XWNdEcGQlTeugCKcUhdDBtThJoA/p6BzCO5qHJcP58PmVD2
iBcbz7LZQ+BLDw5HRNCOsd5N21F5VgGACRUenzX/Piot8Z4y41vXWt3FP6dh+/i6
xQz/pD1Biaaq+GxutOhlHFdwpXc56KpYGrnVoHEAkMdDT84u5OTuz16+wt1FNHIP
ufhpL4iM6IGoqMYnb73IZxvlFNMuZ1bo4uhuvY+bFIZXBV7Xt9TbXtlVG+j/LpqP
pmw09FJGWWc6DrAqcPnCfDhzlXphSIVaYTR6kLdtE6ullUQcfqePmDVok4b5i7Zi
4dEIIXZ1KyWccl8e/6fCuUhPf/qlNdbeXVL2Evud1NYCdpICBTuGbeoGqDsnsU7e
X+Bmp4fSHCdNcHoJeVk+fGg7X4ZsNB5zq4G1reJUZMTq2tvNYS++MXILYDGUN9j0
zsvMExFU5NN5pqpSKv3VeI4AXDYdRRkMBhHhpX27jUgeJ6oDDes59T5iO6Aliw/V
y0elWU3mxe6Rn6R7WHM8or7sX3tWDq6OntJlKg==
-----END PUBLIC KEY-----


================================================
FILE: test/ecdsa-private.pem
================================================
-----BEGIN EC PARAMETERS-----
MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////
/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6
k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+
kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK
fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz
ucrC/GMlUQIBAQ==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIIBaAIBAQQgeg2m9tJJsnURyjTUihohiJahj9ETy3csUIt4EYrV+J2ggfowgfcC
AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////
MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr
vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE
axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W
K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8
YyVRAgEBoUQDQgAEEWluurrkZECnq27UpNauq16f9+5DDMFJZ3HV43Ujc3tcXQ++
N1T/0CAA8ve286f32s7rkqX/pPokI/HBpP5p3g==
-----END EC PRIVATE KEY-----


================================================
FILE: test/ecdsa-public-invalid.pem
================================================
-----BEGIN PUBLIC KEY-----
MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA
AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////
///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd
NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5
RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA
//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABEfZiYJDbghTGQ+KGnHGSl6K
yUqK/BL2uJIg7Z0bx48v6+L7Ve8MCS17eptkMT2e4l5B/ZGDVUHb6uZ5xFROLBw=
-----END PUBLIC KEY-----


================================================
FILE: test/ecdsa-public-x509.pem
================================================
-----BEGIN CERTIFICATE-----
MIIDGjCCAsKgAwIBAgIJANuPNBWwp6wzMAkGByqGSM49BAEwRTELMAkGA1UEBhMC
QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp
dHMgUHR5IEx0ZDAeFw0xNzA2MTAxMTAzMjJaFw0yNzA2MDgxMTAzMjJaMEUxCzAJ
BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGQwggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjO
PQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAA
AAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQaw
zFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i8
5uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2
QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAE
EWluurrkZECnq27UpNauq16f9+5DDMFJZ3HV43Ujc3tcXQ++N1T/0CAA8ve286f3
2s7rkqX/pPokI/HBpP5p3qOBpzCBpDAdBgNVHQ4EFgQUAF43lnAvCztZZGaGMoxs
cp6tpz8wdQYDVR0jBG4wbIAUAF43lnAvCztZZGaGMoxscp6tpz+hSaRHMEUxCzAJ
BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGSCCQDbjzQVsKesMzAMBgNVHRMEBTADAQH/MAkGByqG
SM49BAEDRwAwRAIgV039oh2RtcSwywQ/0dWAwc20NHxrgmKoQ5A3AS5A9d0CIBCV
2AlKDFjmDC7zjldNhWbMcIlSSj71ghhhxeS0F8v1
-----END CERTIFICATE-----


================================================
FILE: test/ecdsa-public.pem
================================================
-----BEGIN PUBLIC KEY-----
MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA
AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////
///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd
NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5
RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA
//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABBFpbrq65GRAp6tu1KTWrqte
n/fuQwzBSWdx1eN1I3N7XF0PvjdU/9AgAPL3tvOn99rO65Kl/6T6JCPxwaT+ad4=
-----END PUBLIC KEY-----


================================================
FILE: test/encoding.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;
var atob = require('atob');

describe('encoding', function() {

  function b64_to_utf8 (str) {
    return decodeURIComponent(escape(atob( str )));
  }

  it('should properly encode the token (utf8)', function () {
    var expected = 'José';
    var token = jwt.sign({ name: expected }, 'shhhhh');
    var decoded_name = JSON.parse(b64_to_utf8(token.split('.')[1])).name;
    expect(decoded_name).to.equal(expected);
  });

  it('should properly encode the token (binary)', function () {
    var expected = 'José';
    var token = jwt.sign({ name: expected }, 'shhhhh', { encoding: 'binary' });
    var decoded_name = JSON.parse(atob(token.split('.')[1])).name;
    expect(decoded_name).to.equal(expected);
  });

  it('should return the same result when decoding', function () {
    var username = '測試';

    var token = jwt.sign({
      username: username
    }, 'test');

    var payload = jwt.verify(token, 'test');

    expect(payload.username).to.equal(username);
  });

});


================================================
FILE: test/expires_format.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('expires option', function() {

  it('should throw on deprecated expiresInSeconds option', function () {
    expect(function () {
      jwt.sign({foo: 123}, '123', { expiresInSeconds: 5 });
    }).to.throw('"expiresInSeconds" is not allowed');
  });

});


================================================
FILE: test/header-kid.test.js
================================================
'use strict';

const jwt = require('../');
const expect = require('chai').expect;
const util = require('util');
const testUtils = require('./test-utils');

function signWithKeyId(keyid, payload, callback) {
  const options = {algorithm: 'HS256'};
  if (keyid !== undefined) {
    options.keyid = keyid;
  }
  testUtils.signJWTHelper(payload, 'secret', options, callback);
}

describe('keyid', function() {
  describe('`jwt.sign` "keyid" option validation', function () {
    [
      true,
      false,
      null,
      -1,
      0,
      1,
      -1.1,
      1.1,
      -Infinity,
      Infinity,
      NaN,
      [],
      ['foo'],
      {},
      {foo: 'bar'},
    ].forEach((keyid) => {
      it(`should error with with value ${util.inspect(keyid)}`, function (done) {
        signWithKeyId(keyid, {}, (err) => {
          testUtils.asyncCheck(done, () => {
            expect(err).to.be.instanceOf(Error);
            expect(err).to.have.property('message', '"keyid" must be a string');
          });
        });
      });
    });

    // undefined needs special treatment because {} is not the same as {keyid: undefined}
    it('should error with with value undefined', function (done) {
      testUtils.signJWTHelper({}, 'secret', {keyid: undefined, algorithm: 'HS256'}, (err) => {
        testUtils.asyncCheck(done, () => {
          expect(err).to.be.instanceOf(Error);
          expect(err).to.have.property('message', '"keyid" must be a string');
        });
      });
    });
  });

  describe('when signing a token', function () {
    it('should not add "kid" header when "keyid" option not provided', function(done) {
      signWithKeyId(undefined, {}, (err, token) => {
        testUtils.asyncCheck(done, () => {
          const decoded = jwt.decode(token, {complete: true});
          expect(err).to.be.null;
          expect(decoded.header).to.not.have.property('kid');
        });
      });
    });

    it('should add "kid" header when "keyid" option is provided and an object payload', function(done) {
      signWithKeyId('foo', {}, (err, token) => {
        testUtils.asyncCheck(done, () => {
          const decoded = jwt.decode(token, {complete: true});
          expect(err).to.be.null;
          expect(decoded.header).to.have.property('kid', 'foo');
        });
      });
    });

    it('should add "kid" header when "keyid" option is provided and a Buffer payload', function(done) {
      signWithKeyId('foo', new Buffer('a Buffer payload'), (err, token) => {
        testUtils.asyncCheck(done, () => {
          const decoded = jwt.decode(token, {complete: true});
          expect(err).to.be.null;
          expect(decoded.header).to.have.property('kid', 'foo');
        });
      });
    });

    it('should add "kid" header when "keyid" option is provided and a string payload', function(done) {
      signWithKeyId('foo', 'a string payload', (err, token) => {
        testUtils.asyncCheck(done, () => {
          const decoded = jwt.decode(token, {complete: true});
          expect(err).to.be.null;
          expect(decoded.header).to.have.property('kid', 'foo');
        });
      });
    });
  });
});


================================================
FILE: test/invalid_exp.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('invalid expiration', function() {

  it('should fail with string', function (done) {
    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxMjMiLCJmb28iOiJhZGFzIn0.cDa81le-pnwJMcJi3o3PBwB7cTJMiXCkizIhxbXAKRg';

    jwt.verify(broken_token, '123', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });

  });

  it('should fail with 0', function (done) {
    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjAsImZvbyI6ImFkYXMifQ.UKxix5T79WwfqAA0fLZr6UrhU-jMES2unwCOFa4grEA';

    jwt.verify(broken_token, '123', function (err) {
      expect(err.name).to.equal('TokenExpiredError');
      done();
    });

  });

  it('should fail with false', function (done) {
    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOmZhbHNlLCJmb28iOiJhZGFzIn0.iBn33Plwhp-ZFXqppCd8YtED77dwWU0h68QS_nEQL8I';

    jwt.verify(broken_token, '123', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });

  });

  it('should fail with true', function (done) {
    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnRydWUsImZvbyI6ImFkYXMifQ.eOWfZCTM5CNYHAKSdFzzk2tDkPQmRT17yqllO-ItIMM';

    jwt.verify(broken_token, '123', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });

  });

  it('should fail with object', function (done) {
    var broken_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOnt9LCJmb28iOiJhZGFzIn0.1JjCTsWLJ2DF-CfESjLdLfKutUt3Ji9cC7ESlcoBHSY';

    jwt.verify(broken_token, '123', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });

  });


});

================================================
FILE: test/invalid_pub.pem
================================================
-----BEGIN CERTIFICATE-----
MIIDJjCCAg6gAwIBAgIJAMyz3mSPlaW4MA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
BAMUCyouYXV0aDAuY29tMB4XDTEzMDQxODE3MDE1MFoXDTI2MTIyNjE3MDE1MFow
FjEUMBIGA1UEAxQLKi5hdXRoMC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDZq1Ua0/BGm+TaBFoftKWeYMWrQG9Fx3g7ikErxljmyOvlwqkiat3q
ixX+Dxw9TFb5gbBjNJ+L3nt4YefJgLsYvsHqkOUxWsB+HM/ulJRVnVrZm1tI3Nbg
xO1BQ7DrGfBpq2KCxtQCaQFRlQJw1+qS5LwrdIvihB7Kc142VElCFFHJ6+09eMUy
jy00Z5pfQr4Am6W6eEOS9ObDbNs4XgKOcWe5khWXj3UStou+VgbAg40XcYht2IbY
gMfKF+VUZOy3+e+aRTqPOBU3MAeb0tvCCPUQJbNAUHgSKVhAvNf8mRwttVsOLT70
anjjeCOd7RKS8fVKBwc2KtgNkghYdPY9AgMBAAGjdzB1MB0GA1UdDgQWBBSi4+X0
+MvCKDdd375mDhx/ZBbJ4DBGBgNVHSMEPzA9gBSi4+X0+MvCKDdd375mDhx/ZBbJ
4KEapBgwFjEUMBIGA1UEAxQLKi5hdXRoMC5jb22CCQDMs95kj5WluDAMBgNVHRME
BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBi0qPe0DzlPSufq+Gdk2Fwf1pGEtjA
D34IxxJ9SX6r1DS/NIP7IOLUnNU8cP8BQWl7i413v29jJsNV457pjdmqf8J7OE9O
eF5Yz1x91gY/27561Iga/TQeIVOlFQAgx66eLfUFFoAig3hz2srZo5TzYBixMJsS
fYMXHPiU7KoLUqYXvpSXIllstQCu51KCC6t9H7wZ92lTES1v76hFY4edQ30sftPo
kjAYWGEhMjPo/r4THcdSMqKXoRtCGEun4pTXid7MJcTgdGDrAJddLWi6SxKecEVB
MhMu4XfUCdxCwqQPjHeJ+zE49A1CUdBB2FN3BNLbmTTwEBgmuwyGRzhj
-----END CERTIFICATE-----


================================================
FILE: test/issue_147.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('issue 147 - signing with a sealed payload', function() {

  it('should put the expiration claim', function () {
    var token = jwt.sign(Object.seal({foo: 123}), '123', { expiresIn: 10 });
    var result = jwt.verify(token, '123');
    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + 10, 0.2);
  });

});

================================================
FILE: test/issue_304.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('issue 304 - verifying values other than strings', function() {

  it('should fail with numbers', function (done) {
    jwt.verify(123, 'foo', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });
  });

  it('should fail with objects', function (done) {
    jwt.verify({ foo: 'bar' }, 'biz', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });
  });

  it('should fail with arrays', function (done) {
    jwt.verify(['foo'], 'bar', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });
  });

  it('should fail with functions', function (done) {
    jwt.verify(function() {}, 'foo', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });
  });

  it('should fail with booleans', function (done) {
    jwt.verify(true, 'foo', function (err) {
      expect(err.name).to.equal('JsonWebTokenError');
      done();
    });
  });

});


================================================
FILE: test/issue_70.tests.js
================================================
var jwt = require('../');

describe('issue 70 - public key start with BEING PUBLIC KEY', function () {

  it('should work', function (done) {
    var fs = require('fs');
    var cert_pub = fs.readFileSync(__dirname + '/rsa-public.pem');
    var cert_priv = fs.readFileSync(__dirname + '/rsa-private.pem');

    var token = jwt.sign({ foo: 'bar' }, cert_priv, { algorithm: 'RS256'});

    jwt.verify(token, cert_pub, done);
  });

});

================================================
FILE: test/jwt.asymmetric_signing.tests.js
================================================
const jwt = require('../index');
const PS_SUPPORTED = require('../lib/psSupported');
const fs = require('fs');
const path = require('path');

const expect = require('chai').expect;
const assert = require('chai').assert;
const ms = require('ms');

function loadKey(filename) {
  return fs.readFileSync(path.join(__dirname, filename));
}

const algorithms = {
  RS256: {
    pub_key: loadKey('pub.pem'),
    priv_key: loadKey('priv.pem'),
    invalid_pub_key: loadKey('invalid_pub.pem')
  },
  ES256: {
    // openssl ecparam -name secp256r1 -genkey -param_enc explicit -out ecdsa-private.pem
    priv_key: loadKey('ecdsa-private.pem'),
    // openssl ec -in ecdsa-private.pem -pubout -out ecdsa-public.pem
    pub_key: loadKey('ecdsa-public.pem'),
    invalid_pub_key: loadKey('ecdsa-public-invalid.pem')
  }
};

if (PS_SUPPORTED) {
  algorithms.PS256 = {
    pub_key: loadKey('pub.pem'),
    priv_key: loadKey('priv.pem'),
    invalid_pub_key: loadKey('invalid_pub.pem')
  };
}


describe('Asymmetric Algorithms', function() {
  Object.keys(algorithms).forEach(function (algorithm) {
    describe(algorithm, function () {
      const pub = algorithms[algorithm].pub_key;
      const priv = algorithms[algorithm].priv_key;

      // "invalid" means it is not the public key for the loaded "priv" key
      const invalid_pub = algorithms[algorithm].invalid_pub_key;

      describe('when signing a token', function () {
        const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm });

        it('should be syntactically valid', function () {
          expect(token).to.be.a('string');
          expect(token.split('.')).to.have.length(3);
        });

        context('asynchronous', function () {
          it('should validate with public key', function (done) {
            jwt.verify(token, pub, function (err, decoded) {
              assert.ok(decoded.foo);
              assert.equal('bar', decoded.foo);
              done();
            });
          });

          it('should throw with invalid public key', function (done) {
            jwt.verify(token, invalid_pub, function (err, decoded) {
              assert.isUndefined(decoded);
              assert.isNotNull(err);
              done();
            });
          });
        });

        context('synchronous', function () {
          it('should validate with public key', function () {
            const decoded = jwt.verify(token, pub);
            assert.ok(decoded.foo);
            assert.equal('bar', decoded.foo);
          });

          it('should throw with invalid public key', function () {
            const jwtVerify = jwt.verify.bind(null, token, invalid_pub)
            assert.throw(jwtVerify, 'invalid signature');
          });
        });

      });

      describe('when signing a token with expiration', function () {
        it('should be valid expiration', function (done) {
          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: '10m' });
          jwt.verify(token, pub, function (err, decoded) {
            assert.isNotNull(decoded);
            assert.isNull(err);
            done();
          });
        });

        it('should be invalid', function (done) {
          // expired token
          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: -1 * ms('10m') });
          jwt.verify(token, pub, function (err, decoded) {
            assert.isUndefined(decoded);
            assert.isNotNull(err);
            assert.equal(err.name, 'TokenExpiredError');
            assert.instanceOf(err.expiredAt, Date);
            assert.instanceOf(err, jwt.TokenExpiredError);
            done();
          });
        });

        it('should NOT be invalid', function (done) {
          // expired token
          const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm, expiresIn: -1 * ms('10m') });

          jwt.verify(token, pub, { ignoreExpiration: true }, function (err, decoded) {
            assert.ok(decoded.foo);
            assert.equal('bar', decoded.foo);
            done();
          });
        });
      });

      describe('when verifying a malformed token', function () {
        it('should throw', function (done) {
          jwt.verify('fruit.fruit.fruit', pub, function (err, decoded) {
            assert.isUndefined(decoded);
            assert.isNotNull(err);
            assert.equal(err.name, 'JsonWebTokenError');
            done();
          });
        });
      });

      describe('when decoding a jwt token with additional parts', function () {
        const token = jwt.sign({ foo: 'bar' }, priv, { algorithm: algorithm });

        it('should throw', function (done) {
          jwt.verify(token + '.foo', pub, function (err, decoded) {
            assert.isUndefined(decoded);
            assert.isNotNull(err);
            done();
          });
        });
      });

      describe('when decoding a invalid jwt token', function () {
        it('should return null', function (done) {
          const payload = jwt.decode('whatever.token');
          assert.isNull(payload);
          done();
        });
      });

      describe('when decoding a valid jwt token', function () {
        it('should return the payload', function (done) {
          const obj = { foo: 'bar' };
          const token = jwt.sign(obj, priv, { algorithm: algorithm });
          const payload = jwt.decode(token);
          assert.equal(payload.foo, obj.foo);
          done();
        });
        it('should return the header and payload and signature if complete option is set', function (done) {
          const obj = { foo: 'bar' };
          const token = jwt.sign(obj, priv, { algorithm: algorithm });
          const decoded = jwt.decode(token, { complete: true });
          assert.equal(decoded.payload.foo, obj.foo);
          assert.deepEqual(decoded.header, { typ: 'JWT', alg: algorithm });
          assert.ok(typeof decoded.signature == 'string');
          done();
        });
      });
    });
  });

  describe('when signing a token with an unsupported private key type', function () {
    it('should throw an error', function() {
      const obj = { foo: 'bar' };
      const key = loadKey('dsa-private.pem');
      const algorithm = 'RS256';

      expect(function() {
        jwt.sign(obj, key, { algorithm });
      }).to.throw('Unknown key type "dsa".');
    });
  });

  describe('when signing a token with an incorrect private key type', function () {
    it('should throw a validation error if key validation is enabled', function() {
      const obj = { foo: 'bar' };
      const key = loadKey('rsa-private.pem');
      const algorithm = 'ES256';

      expect(function() {
        jwt.sign(obj, key, { algorithm });
      }).to.throw(/"alg" parameter for "rsa" key type must be one of:/);
    });

    it('should throw an unknown error if key validation is disabled', function() {
      const obj = { foo: 'bar' };
      const key = loadKey('rsa-private.pem');
      const algorithm = 'ES256';

      expect(function() {
        jwt.sign(obj, key, { algorithm, allowInvalidAsymmetricKeyTypes: true });
      }).to.not.throw(/"alg" parameter for "rsa" key type must be one of:/);
    });
  });
});


================================================
FILE: test/jwt.hs.tests.js
================================================
const jwt = require('../index');

const jws = require('jws');
const expect = require('chai').expect;
const assert = require('chai').assert;
const { generateKeyPairSync } = require('crypto')

describe('HS256', function() {

  describe("when signing using HS256", function () {
    it('should throw if the secret is an asymmetric key', function () {
      const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });

      expect(function () {
        jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'HS256' })
      }).to.throw(Error, 'must be a symmetric key')
    })

    it('should throw if the payload is undefined', function () {
      expect(function () {
        jwt.sign(undefined, "secret", { algorithm: 'HS256' })
      }).to.throw(Error, 'payload is required')
    })

    it('should throw if options is not a plain object', function () {
      expect(function () {
        jwt.sign({ foo: 'bar' }, "secret", ['HS256'])
      }).to.throw(Error, 'Expected "options" to be a plain object')
    })
  })

  describe('with a token signed using HS256', function() {
    var secret = 'shhhhhh';

    var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });

    it('should be syntactically valid', function() {
      expect(token).to.be.a('string');
      expect(token.split('.')).to.have.length(3);
    });

    it('should be able to validate without options', function(done) {
      var callback = function(err, decoded) {
        assert.ok(decoded.foo);
        assert.equal('bar', decoded.foo);
        done();
      };
      callback.issuer = "shouldn't affect";
      jwt.verify(token, secret, callback );
    });

    it('should validate with secret', function(done) {
      jwt.verify(token, secret, function(err, decoded) {
        assert.ok(decoded.foo);
        assert.equal('bar', decoded.foo);
        done();
      });
    });

    it('should throw with invalid secret', function(done) {
      jwt.verify(token, 'invalid secret', function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

    it('should throw with secret and token not signed', function(done) {
      const header = { alg: 'none' };
      const payload = { foo: 'bar' };
      const token = jws.sign({ header, payload, secret: 'secret', encoding: 'utf8' });
      jwt.verify(token, 'secret', function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

    it('should throw with falsy secret and token not signed', function(done) {
      const header = { alg: 'none' };
      const payload = { foo: 'bar' };
      const token = jws.sign({ header, payload, secret: null, encoding: 'utf8' });
      jwt.verify(token, 'secret', function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

    it('should throw when verifying null', function(done) {
      jwt.verify(null, 'secret', function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

    it('should return an error when the token is expired', function(done) {
      var token = jwt.sign({ exp: 1 }, secret, { algorithm: 'HS256' });
      jwt.verify(token, secret, { algorithm: 'HS256' }, function(err, decoded) {
        assert.isUndefined(decoded);
        assert.isNotNull(err);
        done();
      });
    });

    it('should NOT return an error when the token is expired with "ignoreExpiration"', function(done) {
      var token = jwt.sign({ exp: 1, foo: 'bar' }, secret, { algorithm: 'HS256' });
      jwt.verify(token, secret, { algorithm: 'HS256', ignoreExpiration: true }, function(err, decoded) {
        assert.ok(decoded.foo);
        assert.equal('bar', decoded.foo);
        assert.isNull(err);
        done();
      });
    });

    it('should default to HS256 algorithm when no options are passed', function() {
      var token = jwt.sign({ foo: 'bar' }, secret);
      var verifiedToken = jwt.verify(token, secret);
      assert.ok(verifiedToken.foo);
      assert.equal('bar', verifiedToken.foo);
    });
  });

  describe('should fail verification gracefully with trailing space in the jwt', function() {
    var secret = 'shhhhhh';
    var token  = jwt.sign({ foo: 'bar' }, secret, { algorithm: 'HS256' });

    it('should return the "invalid token" error', function(done) {
      var malformedToken = token + ' '; // corrupt the token by adding a space
      jwt.verify(malformedToken, secret, { algorithm: 'HS256', ignoreExpiration: true }, function(err) {
        assert.isNotNull(err);
        assert.equal('JsonWebTokenError', err.name);
        assert.equal('invalid token', err.message);
        done();
      });
    });
  });

});


================================================
FILE: test/jwt.malicious.tests.js
================================================
const jwt = require('../index');
const crypto = require("crypto");
const {expect} = require('chai');
const JsonWebTokenError = require("../lib/JsonWebTokenError");

describe('when verifying a malicious token', function () {
  // attacker has access to the public rsa key, but crafts the token as HS256
  // with kid set to the id of the rsa key, instead of the id of the hmac secret.
  // const maliciousToken = jwt.sign(
  //   {foo: 'bar'},
  //   pubRsaKey,
  //   {algorithm: 'HS256', keyid: 'rsaKeyId'}
  // );
  // consumer accepts self signed tokens (HS256) and third party tokens (RS256)
  const options = {algorithms: ['RS256', 'HS256']};

  const {
    publicKey: pubRsaKey
  } = crypto.generateKeyPairSync('rsa', {modulusLength: 2048});

  it('should not allow HMAC verification with an RSA key in KeyObject format', function () {
    const maliciousToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJzYUtleUlkIn0.eyJmb28iOiJiYXIiLCJpYXQiOjE2NTk1MTA2MDh9.cOcHI1TXPbxTMlyVTfjArSWskrmezbrG8iR7uJHwtrQ';

    expect(() => jwt.verify(maliciousToken, pubRsaKey, options)).to.throw(JsonWebTokenError, 'must be a symmetric key');
  })

  it('should not allow HMAC verification with an RSA key in PEM format', function () {
    const maliciousToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJzYUtleUlkIn0.eyJmb28iOiJiYXIiLCJpYXQiOjE2NTk1MTA2MDh9.cOcHI1TXPbxTMlyVTfjArSWskrmezbrG8iR7uJHwtrQ';

    expect(() => jwt.verify(maliciousToken, pubRsaKey.export({type: 'spki', format: 'pem'}), options)).to.throw(JsonWebTokenError, 'must be a symmetric key');
  })

  it('should not allow arbitrary execution from malicious Buffers containing objects with overridden toString functions', function () {
    const token = jwt.sign({"foo": "bar"}, 'secret')
    const maliciousBuffer = {toString: () => {throw new Error("Arbitrary Code Execution")}}

    expect(() => jwt.verify(token, maliciousBuffer)).to.throw(Error, 'not valid key material');
  })
})


================================================
FILE: test/noTimestamp.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('noTimestamp', function() {

  it('should work with string', function () {
    var token = jwt.sign({foo: 123}, '123', { expiresIn: '5m' , noTimestamp: true });
    var result = jwt.verify(token, '123');
    expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + (5*60), 0.5);
  });

});


================================================
FILE: test/non_object_values.tests.js
================================================
var jwt = require('../index');
var expect = require('chai').expect;

describe('non_object_values values', function() {

  it('should work with string', function () {
    var token = jwt.sign('hello', '123');
    var result = jwt.verify(token, '123');
    expect(result).to.equal('hello');
  });

  it('should work with number', function () {
    var token = jwt.sign(123, '123');
    var result = jwt.verify(token, '123');
    expect(result).to.equal('123');
  });

});


================================================
FILE: test/option-complete.test.js
================================================
'use strict';

const jws = require('jws');
const expect = require('chai').expect;
const path = require('path');
const fs = require('fs');
const testUtils = require('./test-utils')

describe('complete option', function () {
  const secret = fs.readFileSync(path.join(__dirname, 'priv.pem'));
  const pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));

  con
Download .txt
gitextract_nrhlur7n/

├── .commitlintrc.json
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github/
│   └── workflows/
│       ├── commitlint.yml
│       ├── prepare-release.yml
│       ├── release.yml
│       ├── sca-scan.yml
│       └── test.yml
├── .gitignore
├── .husky/
│   └── commit-msg
├── .npmignore
├── .releaserc.json
├── CHANGELOG.md
├── CODEOWNERS
├── LICENSE
├── README.md
├── bin/
│   └── changelog
├── decode.js
├── index.js
├── lib/
│   ├── JsonWebTokenError.js
│   ├── NotBeforeError.js
│   ├── TokenExpiredError.js
│   ├── asymmetricKeyDetailsSupported.js
│   ├── psSupported.js
│   ├── rsaPssKeyDetailsSupported.js
│   ├── timespan.js
│   └── validateAsymmetricKey.js
├── opslevel.yml
├── package.json
├── sign.js
├── test/
│   ├── .eslintrc.json
│   ├── async_sign.tests.js
│   ├── buffer.tests.js
│   ├── claim-aud.test.js
│   ├── claim-exp.test.js
│   ├── claim-iat.test.js
│   ├── claim-iss.test.js
│   ├── claim-jti.test.js
│   ├── claim-nbf.test.js
│   ├── claim-private.tests.js
│   ├── claim-sub.tests.js
│   ├── decoding.tests.js
│   ├── dsa-private.pem
│   ├── dsa-public.pem
│   ├── ecdsa-private.pem
│   ├── ecdsa-public-invalid.pem
│   ├── ecdsa-public-x509.pem
│   ├── ecdsa-public.pem
│   ├── encoding.tests.js
│   ├── expires_format.tests.js
│   ├── header-kid.test.js
│   ├── invalid_exp.tests.js
│   ├── invalid_pub.pem
│   ├── issue_147.tests.js
│   ├── issue_304.tests.js
│   ├── issue_70.tests.js
│   ├── jwt.asymmetric_signing.tests.js
│   ├── jwt.hs.tests.js
│   ├── jwt.malicious.tests.js
│   ├── noTimestamp.tests.js
│   ├── non_object_values.tests.js
│   ├── option-complete.test.js
│   ├── option-maxAge.test.js
│   ├── option-nonce.test.js
│   ├── prime256v1-private.pem
│   ├── priv.pem
│   ├── pub.pem
│   ├── rsa-private.pem
│   ├── rsa-pss-invalid-salt-length-private.pem
│   ├── rsa-pss-private.pem
│   ├── rsa-public-key.pem
│   ├── rsa-public-key.tests.js
│   ├── rsa-public.pem
│   ├── schema.tests.js
│   ├── secp384r1-private.pem
│   ├── secp521r1-private.pem
│   ├── set_headers.tests.js
│   ├── test-utils.js
│   ├── undefined_secretOrPublickey.tests.js
│   ├── validateAsymmetricKey.tests.js
│   ├── verify.tests.js
│   └── wrong_alg.tests.js
└── verify.js
Download .txt
SYMBOL INDEX (39 symbols across 18 files)

FILE: lib/validateAsymmetricKey.js
  constant ASYMMETRIC_KEY_DETAILS_SUPPORTED (line 1) | const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('./asymmetricKeyDetails...
  constant RSA_PSS_KEY_DETAILS_SUPPORTED (line 2) | const RSA_PSS_KEY_DETAILS_SUPPORTED = require('./rsaPssKeyDetailsSupport...

FILE: sign.js
  constant PS_SUPPORTED (line 2) | const PS_SUPPORTED = require('./lib/psSupported');
  constant SUPPORTED_ALGS (line 14) | const SUPPORTED_ALGS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES...
  function validate (line 42) | function validate(schema, allowUnknown, object, parameterName) {
  function validateOptions (line 61) | function validateOptions(options) {
  function validatePayload (line 65) | function validatePayload(payload) {
  function failure (line 103) | function failure(err) {

FILE: test/claim-aud.test.js
  function signWithAudience (line 8) | function signWithAudience(audience, payload, callback) {
  function verifyWithAudience (line 17) | function verifyWithAudience(token, audience,  callback) {

FILE: test/claim-exp.test.js
  function signWithExpiresIn (line 10) | function signWithExpiresIn(expiresIn, payload, callback) {

FILE: test/claim-iat.test.js
  function signWithIssueAt (line 10) | function signWithIssueAt(issueAt, options, callback) {
  function verifyWithIssueAt (line 21) | function verifyWithIssueAt(token, maxAge, options, secret, callback) {

FILE: test/claim-iss.test.js
  function signWithIssuer (line 8) | function signWithIssuer(issuer, payload, callback) {

FILE: test/claim-jti.test.js
  function signWithJWTId (line 8) | function signWithJWTId(jwtid, payload, callback) {

FILE: test/claim-nbf.test.js
  function signWithNotBefore (line 10) | function signWithNotBefore(notBefore, payload, callback) {

FILE: test/claim-private.tests.js
  function signWithPayload (line 7) | function signWithPayload(payload, callback) {

FILE: test/claim-sub.tests.js
  function signWithSubject (line 8) | function signWithSubject(subject, payload, callback) {

FILE: test/encoding.tests.js
  function b64_to_utf8 (line 7) | function b64_to_utf8 (str) {

FILE: test/header-kid.test.js
  function signWithKeyId (line 8) | function signWithKeyId(keyid, payload, callback) {

FILE: test/jwt.asymmetric_signing.tests.js
  constant PS_SUPPORTED (line 2) | const PS_SUPPORTED = require('../lib/psSupported');
  function loadKey (line 10) | function loadKey(filename) {

FILE: test/rsa-public-key.tests.js
  constant PS_SUPPORTED (line 2) | const PS_SUPPORTED = require('../lib/psSupported');

FILE: test/schema.tests.js
  function sign (line 14) | function sign(options, secretOrPrivateKey) {
  function sign (line 63) | function sign(payload) {

FILE: test/test-utils.js
  function asyncCheck (line 12) | function asyncCheck(done, testFunction) {
  function expectEqualError (line 28) | function expectEqualError(e1, e2) {
  function base64UrlEncode (line 44) | function base64UrlEncode(str) {
  function verifyJWTHelper (line 59) | function verifyJWTHelper(jwtString, secretOrPrivateKey, options, callbac...
  function signJWTHelper (line 96) | function signJWTHelper(payload, secretOrPrivateKey, options, callback) {

FILE: test/validateAsymmetricKey.tests.js
  constant PS_SUPPORTED (line 2) | const PS_SUPPORTED = require('../lib/psSupported');
  constant ASYMMETRIC_KEY_DETAILS_SUPPORTED (line 3) | const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('../lib/asymmetricKeyDe...
  constant RSA_PSS_KEY_DETAILS_SUPPORTED (line 4) | const RSA_PSS_KEY_DETAILS_SUPPORTED = require('../lib/rsaPssKeyDetailsSu...
  function loadKey (line 10) | function loadKey(filename) {

FILE: verify.js
  constant PS_SUPPORTED (line 7) | const PS_SUPPORTED = require('./lib/psSupported');
  constant PUB_KEY_ALGS (line 11) | const PUB_KEY_ALGS = ['RS256', 'RS384', 'RS512'];
  constant EC_KEY_ALGS (line 12) | const EC_KEY_ALGS = ['ES256', 'ES384', 'ES512'];
  constant RSA_KEY_ALGS (line 13) | const RSA_KEY_ALGS = ['RS256', 'RS384', 'RS512'];
  constant HS_ALGS (line 14) | const HS_ALGS = ['HS256', 'HS384', 'HS512'];
Condensed preview — 84 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (254K chars).
[
  {
    "path": ".commitlintrc.json",
    "chars": 53,
    "preview": "{\n  \"extends\": [\"@commitlint/config-conventional\"]\n}\n"
  },
  {
    "path": ".editorconfig",
    "chars": 41,
    "preview": "[*]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".eslintignore",
    "chars": 23,
    "preview": ".nyc_output/\ncoverage/\n"
  },
  {
    "path": ".eslintrc.json",
    "chars": 461,
    "preview": "{\n  \"root\": true,\n  \"parserOptions\": {\n    \"ecmaVersion\": 6\n  },\n  \"env\": {\n    \"es6\": true,\n    \"node\": true\n  },\n  \"ru"
  },
  {
    "path": ".github/workflows/commitlint.yml",
    "chars": 674,
    "preview": "name: Lint Commits\n\non:\n  pull_request:\n\njobs:\n  commitlint:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkou"
  },
  {
    "path": ".github/workflows/prepare-release.yml",
    "chars": 2313,
    "preview": "name: Prepare Release\n\non:\n  push:\n    branches:\n      - master\n\nconcurrency:\n  group: prepare-release\n  cancel-in-progr"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1948,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\npermissions:\n  contents: write\n  issues: write\n  pull-requests:"
  },
  {
    "path": ".github/workflows/sca-scan.yml",
    "chars": 200,
    "preview": "name: Snyk Scan\n\non:\n  push:\n    branches: [\"master\"]\n\njobs:\n  snyk-cli:\n    uses: auth0/devsecops-tooling/.github/workf"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 765,
    "preview": "name: Test\n\non:\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: tr"
  },
  {
    "path": ".gitignore",
    "chars": 62,
    "preview": "node_modules\n.DS_Store\n.nyc_output\ncoverage\npackage-lock.json\n"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 35,
    "preview": "npx --no -- commitlint --edit ${1}\n"
  },
  {
    "path": ".npmignore",
    "chars": 12,
    "preview": "opslevel.yml"
  },
  {
    "path": ".releaserc.json",
    "chars": 675,
    "preview": "{\n  \"branches\": [\n    \"master\"\n  ],\n  \"plugins\": [\n    \"@semantic-release/commit-analyzer\",\n    \"@semantic-release/relea"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 41594,
    "preview": "# Change Log\n\n\nAll notable changes to this project will be documented in this file starting from version **v4.0.0**.\nThi"
  },
  {
    "path": "CODEOWNERS",
    "chars": 50,
    "preview": "* @auth0/project-iam-protocols-engineer-codeowner\n"
  },
  {
    "path": "LICENSE",
    "chars": 1121,
    "preview": "The MIT License (MIT)\n \nCopyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)\n \nPermission is hereby gra"
  },
  {
    "path": "README.md",
    "chars": 17709,
    "preview": "# jsonwebtoken\n\n| **Build**                                                                                             "
  },
  {
    "path": "bin/changelog",
    "chars": 1419,
    "preview": "#!/usr/bin/env node\n\nvar changelog = require('conventional-changelog');\nvar semver_regex = /\\bv?(?:0|[1-9][0-9]*)\\.(?:0|"
  },
  {
    "path": "decode.js",
    "chars": 767,
    "preview": "var jws = require('jws');\n\nmodule.exports = function (jwt, options) {\n  options = options || {};\n  var decoded = jws.dec"
  },
  {
    "path": "index.js",
    "chars": 276,
    "preview": "module.exports = {\n  decode: require('./decode'),\n  verify: require('./verify'),\n  sign: require('./sign'),\n  JsonWebTok"
  },
  {
    "path": "lib/JsonWebTokenError.js",
    "chars": 428,
    "preview": "var JsonWebTokenError = function (message, error) {\n  Error.call(this, message);\n  if(Error.captureStackTrace) {\n    Err"
  },
  {
    "path": "lib/NotBeforeError.js",
    "chars": 362,
    "preview": "var JsonWebTokenError = require('./JsonWebTokenError');\n\nvar NotBeforeError = function (message, date) {\n  JsonWebTokenE"
  },
  {
    "path": "lib/TokenExpiredError.js",
    "chars": 395,
    "preview": "var JsonWebTokenError = require('./JsonWebTokenError');\n\nvar TokenExpiredError = function (message, expiredAt) {\n  JsonW"
  },
  {
    "path": "lib/asymmetricKeyDetailsSupported.js",
    "chars": 99,
    "preview": "const semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '>=15.7.0');\n"
  },
  {
    "path": "lib/psSupported.js",
    "chars": 107,
    "preview": "var semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '^6.12.0 || >=8.0.0');\n"
  },
  {
    "path": "lib/rsaPssKeyDetailsSupported.js",
    "chars": 99,
    "preview": "const semver = require('semver');\n\nmodule.exports = semver.satisfies(process.version, '>=16.9.0');\n"
  },
  {
    "path": "lib/timespan.js",
    "chars": 412,
    "preview": "var ms = require('ms');\n\nmodule.exports = function (time, iat) {\n  var timestamp = iat || Math.floor(Date.now() / 1000);"
  },
  {
    "path": "lib/validateAsymmetricKey.js",
    "chars": 2238,
    "preview": "const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('./asymmetricKeyDetailsSupported');\nconst RSA_PSS_KEY_DETAILS_SUPPORTED"
  },
  {
    "path": "opslevel.yml",
    "chars": 66,
    "preview": "---\nversion: 1\nrepository:\n  owner: iam_protocols\n  tier:\n  tags:\n"
  },
  {
    "path": "package.json",
    "chars": 1634,
    "preview": "{\n  \"name\": \"jsonwebtoken\",\n  \"version\": \"9.0.3\",\n  \"description\": \"JSON Web Token implementation (symmetric and asymmet"
  },
  {
    "path": "sign.js",
    "chars": 9350,
    "preview": "const timespan = require('./lib/timespan');\nconst PS_SUPPORTED = require('./lib/psSupported');\nconst validateAsymmetricK"
  },
  {
    "path": "test/.eslintrc.json",
    "chars": 37,
    "preview": "{\n  \"env\": {\n    \"mocha\": true\n  }\n}\n"
  },
  {
    "path": "test/async_sign.tests.js",
    "chars": 5851,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar jws = require('jws');\nvar PS_SUPPORTED = require"
  },
  {
    "path": "test/buffer.tests.js",
    "chars": 325,
    "preview": "var jwt = require(\"../.\");\nvar assert = require('chai').assert;\n\ndescribe('buffer payload', function () {\n  it('should w"
  },
  {
    "path": "test/claim-aud.test.js",
    "chars": 17443,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/claim-exp.test.js",
    "chars": 11329,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst "
  },
  {
    "path": "test/claim-iat.test.js",
    "chars": 8421,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst "
  },
  {
    "path": "test/claim-iss.test.js",
    "chars": 7247,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/claim-jti.test.js",
    "chars": 5150,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/claim-nbf.test.js",
    "chars": 11222,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst "
  },
  {
    "path": "test/claim-private.tests.js",
    "chars": 2046,
    "preview": "'use strict';\n\nconst expect = require('chai').expect;\nconst util = require('util');\nconst testUtils = require('./test-ut"
  },
  {
    "path": "test/claim-sub.tests.js",
    "chars": 5098,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/decoding.tests.js",
    "chars": 255,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('decoding', function() {\n\n  it('should not"
  },
  {
    "path": "test/dsa-private.pem",
    "chars": 2268,
    "preview": "-----BEGIN DSA PRIVATE KEY-----\nMIIGWAIBAAKCAgEArzbPbt//BQpsYsnoZR4R9nXgcuvcXoH8WZjRsb4ZPfVJGchG\n7CfRMlG0HR34vcUpehNj5pA"
  },
  {
    "path": "test/dsa-public.pem",
    "chars": 2238,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIGSDCCBDoGByqGSM44BAEwggQtAoICAQCvNs9u3/8FCmxiyehlHhH2deBy69xe\ngfxZmNGxvhk99UkZyEbsJ9EyUbQd"
  },
  {
    "path": "test/ecdsa-private.pem",
    "chars": 956,
    "preview": "-----BEGIN EC PARAMETERS-----\nMIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////\n/////zBbBCD/////AAAAAQAAA"
  },
  {
    "path": "test/ecdsa-public-invalid.pem",
    "chars": 507,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\nAAAAAAAAAAAA////////////////"
  },
  {
    "path": "test/ecdsa-public-x509.pem",
    "chars": 1135,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDGjCCAsKgAwIBAgIJANuPNBWwp6wzMAkGByqGSM49BAEwRTELMAkGA1UEBhMC\nQVUxEzARBgNVBAgTClNvbWUtU3R"
  },
  {
    "path": "test/ecdsa-public.pem",
    "chars": 507,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\nAAAAAAAAAAAA////////////////"
  },
  {
    "path": "test/encoding.tests.js",
    "chars": 1048,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar atob = require('atob');\n\ndescribe('encoding', fu"
  },
  {
    "path": "test/expires_format.tests.js",
    "chars": 333,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('expires option', function() {\n\n  it('shou"
  },
  {
    "path": "test/header-kid.test.js",
    "chars": 3139,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/invalid_exp.tests.js",
    "chars": 1755,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('invalid expiration', function() {\n\n  it('"
  },
  {
    "path": "test/invalid_pub.pem",
    "chars": 1151,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIJAMyz3mSPlaW4MA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV\nBAMUCyouYXV0aDAuY29tMB4XDTE"
  },
  {
    "path": "test/issue_147.tests.js",
    "chars": 400,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('issue 147 - signing with a sealed payload"
  },
  {
    "path": "test/issue_304.tests.js",
    "chars": 1065,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('issue 304 - verifying values other than s"
  },
  {
    "path": "test/issue_70.tests.js",
    "chars": 433,
    "preview": "var jwt = require('../');\n\ndescribe('issue 70 - public key start with BEING PUBLIC KEY', function () {\n\n  it('should wor"
  },
  {
    "path": "test/jwt.asymmetric_signing.tests.js",
    "chars": 7227,
    "preview": "const jwt = require('../index');\nconst PS_SUPPORTED = require('../lib/psSupported');\nconst fs = require('fs');\nconst pat"
  },
  {
    "path": "test/jwt.hs.tests.js",
    "chars": 4803,
    "preview": "const jwt = require('../index');\n\nconst jws = require('jws');\nconst expect = require('chai').expect;\nconst assert = requ"
  },
  {
    "path": "test/jwt.malicious.tests.js",
    "chars": 1959,
    "preview": "const jwt = require('../index');\nconst crypto = require(\"crypto\");\nconst {expect} = require('chai');\nconst JsonWebTokenE"
  },
  {
    "path": "test/noTimestamp.tests.js",
    "chars": 376,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('noTimestamp', function() {\n\n  it('should "
  },
  {
    "path": "test/non_object_values.tests.js",
    "chars": 470,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('non_object_values values', function() {\n\n"
  },
  {
    "path": "test/option-complete.test.js",
    "chars": 1792,
    "preview": "'use strict';\n\nconst jws = require('jws');\nconst expect = require('chai').expect;\nconst path = require('path');\nconst fs"
  },
  {
    "path": "test/option-maxAge.test.js",
    "chars": 1882,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\nconst "
  },
  {
    "path": "test/option-nonce.test.js",
    "chars": 1333,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst util = require('util');\nconst te"
  },
  {
    "path": "test/prime256v1-private.pem",
    "chars": 227,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMP1Xt/ic2jAHJva2Pll866d1jYL+dk3VdLytEU1+LFmoAoGCCqGSM49\nAwEHoUQDQgAEvIywoA1H1a2X"
  },
  {
    "path": "test/priv.pem",
    "chars": 1679,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvtH4wKLYlIXZlfYQFJtXZVC3fD8XMarzwvb/fHUyJ6NvNStN\n+H7GHp3/QhZbSaRyqK5hu5x"
  },
  {
    "path": "test/pub.pem",
    "chars": 1346,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMKR/NsyfcazMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21"
  },
  {
    "path": "test/rsa-private.pem",
    "chars": 1679,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ\n7rBasuLI8AcfX5/10scSfQN"
  },
  {
    "path": "test/rsa-pss-invalid-salt-length-private.pem",
    "chars": 1777,
    "preview": "-----BEGIN PRIVATE KEY-----\nMIIE8gIBADBCBgkqhkiG9w0BAQowNaAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI\nhvcNAQEIMA0GCWCGSAFlAwQCAQU"
  },
  {
    "path": "test/rsa-pss-private.pem",
    "chars": 1773,
    "preview": "-----BEGIN PRIVATE KEY-----\nMIIE8QIBADBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZI\nhvcNAQEIMA0GCWCGSAFlAwQCAQU"
  },
  {
    "path": "test/rsa-public-key.pem",
    "chars": 426,
    "preview": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAvzoCEC2rpSpJQaWZbUmlsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ7rBa\nsuLI8AcfX5/10scSfQNCsTLV"
  },
  {
    "path": "test/rsa-public-key.tests.js",
    "chars": 1693,
    "preview": "const jwt = require('../');\nconst PS_SUPPORTED = require('../lib/psSupported');\nconst expect = require('chai').expect;\nc"
  },
  {
    "path": "test/rsa-public.pem",
    "chars": 451,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzoCEC2rpSpJQaWZbUml\nsDNwp83Jr4fi6KmBWIwnj1MZ6CUQ"
  },
  {
    "path": "test/schema.tests.js",
    "chars": 2574,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\nvar fs = require('fs');\nvar PS_SUPPORTED = require('"
  },
  {
    "path": "test/secp384r1-private.pem",
    "chars": 288,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDCez58vZHVp+ArI7/fe835GAtRzE0AtrxGgQAY1U/uk2SQOaSw1ph61\n3Unr0ygS172gBwYFK4EEACKh"
  },
  {
    "path": "test/secp521r1-private.pem",
    "chars": 365,
    "preview": "-----BEGIN EC PRIVATE KEY-----\nMIHcAgEBBEIBlWXKBKKCgTgf7+NS09TMv7/NO3RtMBn9xTe+46oNNNK405lrZ9mz\nWYtlsYvkdsc2Cx3v5V8JegaC"
  },
  {
    "path": "test/set_headers.tests.js",
    "chars": 577,
    "preview": "var jwt = require('../index');\nvar expect = require('chai').expect;\n\ndescribe('set header', function() {\n\n  it('should a"
  },
  {
    "path": "test/test-utils.js",
    "chars": 3611,
    "preview": "'use strict';\n\nconst jwt = require('../');\nconst expect = require('chai').expect;\nconst sinon = require('sinon');\n\n/**\n "
  },
  {
    "path": "test/undefined_secretOrPublickey.tests.js",
    "chars": 677,
    "preview": "var jwt = require('../index');\nvar JsonWebTokenError = require('../lib/JsonWebTokenError');\nvar expect = require('chai')"
  },
  {
    "path": "test/validateAsymmetricKey.tests.js",
    "chars": 5387,
    "preview": "const validateAsymmetricKey = require('../lib/validateAsymmetricKey');\nconst PS_SUPPORTED = require('../lib/psSupported'"
  },
  {
    "path": "test/verify.tests.js",
    "chars": 11151,
    "preview": "const jwt = require('../index');\nconst jws = require('jws');\nconst fs = require('fs');\nconst path = require('path');\ncon"
  },
  {
    "path": "test/wrong_alg.tests.js",
    "chars": 1799,
    "preview": "var fs = require('fs');\nvar path = require('path');\nvar jwt = require('../index');\nvar JsonWebTokenError = require('../l"
  },
  {
    "path": "verify.js",
    "chars": 8612,
    "preview": "const JsonWebTokenError = require('./lib/JsonWebTokenError');\nconst NotBeforeError = require('./lib/NotBeforeError');\nco"
  }
]

About this extraction

This page contains the full source code of the auth0/node-jsonwebtoken GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 84 files (237.0 KB), approximately 75.3k tokens, and a symbol index with 39 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!