_ERROR_MESSAGE);

    });
    it('throws when there is no payload', function() {
      assert.throws(jwt.decode('test..test'), IDTOKEN_ERROR_MESSAGE);

    });
    it('throws when there is no signature', function() {
      assert.throws(jwt.decode('test.test.'), IDTOKEN_ERROR_MESSAGE);

    });
  })
});

describe('jwt.verify', function() {
  var expectedOptions;

  beforeEach(function() {
    expectedOptions = Object.assign({}, payload);
    expectedOptions.aud = expectations.clientId;
    expectedOptions.maxAge = 123
  });

  it('should throw when no id token is present', function(done) {
    var EXPECTED_ERROR_MESSAGE = 'ID token is required but missing';
    try {
      jwt.verify()
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when no Issuer is present in the claim', function(done) {
    var EXPECTED_ERROR_MESSAGE = 'Issuer (iss) claim must be a string present in the ID token';
    try {
      jwt.verify(generateJWT({ iss: undefined }))
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when the expected issuer is not in the claim', function(done) {
    var EXPECTED_ERROR_MESSAGE = 'Issuer (iss) claim mismatch in the ID token; expected "ExpectedIssuer", found "https://tokens-test.auth0.com/"';
    try {
      jwt.verify(generateJWT({}), { iss: 'ExpectedIssuer' })
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when the claim has no Subject', function(done) {
    var EXPECTED_ERROR_MESSAGE = 'Subject (sub) claim must be a string present in the ID token';
    try {
      jwt.verify(generateJWT({ sub: undefined }), payload)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when the alg is neither rs256 or hs256', function(done) {
    var token = 'eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJodHRwczovL3Rva2Vucy10ZXN0LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHwxMjM0NTY3ODkiLCJhdWQiOiJ0b2tlbnMtdGVzdC0xMjMifQ.cZ4qDwoKdKQx8DtD-F-xVKCxd3rz58wSJh3k28z5qnpzm4x3xRiyHCuUvtxmL2aPdBQ37Zt8Mt5drd9hZhNzFQ';
    var EXPECTED_ERROR_MESSAGE = 'Signature algorithm of "HS512" is not supported. Expected the ID token to be signed with "RS256" or "HS256".';
    try {
      jwt.verify(token, payload)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when the audience is not a string or array', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Audience (aud) claim must be a string or array of strings present in the ID token';
    try {
      jwt.verify(generateJWT({ aud: undefined }), payload)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when expected audience doesnt match claim audience', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Audience (aud) claim mismatch in the ID token; expected "expectedAudience" but was not one of "tokens-test-123, external-test-999"';
    try {
      expectedOptions.aud = 'expectedAudience';
      jwt.verify(generateJWT({}), expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when azp claim not found when aud has multiple values', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values';
    try {
      var token = generateJWT({ azp: undefined });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when azp claim doesnt match the expected aud', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Authorized Party (azp) claim mismatch in the ID token; expected "external-test-999", found "tokens-test-123"';
    try {
      var token = generateJWT({});
      expectedOptions.aud = expectations.clientIdAlt;
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });

  it('should throw when nonce is in options, but missing from claim', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Nonce (nonce) claim must be a string present in the ID token';
    try {
      var token = generateJWT({ nonce: undefined });

      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when nonce claim doesnt match nonce expected', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Nonce (nonce) claim mismatch in the ID token; expected "noncey", found "notExpectedNonce"';
    try {
      var token = generateJWT({ nonce: 'notExpectedNonce' });
      expectedOptions.nonce = 'noncey';
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when auth_time is not a number', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified';
    try {
      var token = generateJWT({ auth_time: undefined });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when exp is not a number', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Expiration Time (exp) claim must be a number present in the ID token';
    try {
      var token = generateJWT({ exp: 'not a number' });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
  it('should throw when exp has passed', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'is after expiration time';
    try {
      var token = generateJWT({ exp: yesterday() });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert(error.message.includes(EXPECTED_ERROR_MESSAGE));
      done();
    }
  });
  it('should throw when idtoken indicates too much time has passed', function (done) {
    var EXPECTED_ERROR_MESSAGE = 'Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication.';
    try {
      var token = generateJWT({ auth_time: yesterday() });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert(error.message.includes(EXPECTED_ERROR_MESSAGE));
      done();
    }
  });
  it('should throw when Issued At is missing', function(done) {
    var EXPECTED_ERROR_MESSAGE = 'Issued At (iat) claim must be a number present in the ID token';
    try {
      var token = generateJWT({ iat: undefined });
      jwt.verify(token, expectedOptions)
      done(new Error('Should have thrown error: ' + EXPECTED_ERROR_MESSAGE));
    } catch (error) {
      assert.equal(error.message, EXPECTED_ERROR_MESSAGE);
      done();
    }
  });
});
