mongodb/node-mongodb-native · critical · MongoRuntimeError

Server returned an invalid signature

Error message

Server returned an invalid signature

What it means

Thrown by continueScramConversation() (scram.ts:189) as a MongoRuntimeError after the final saslContinue when the server's signature (parsedResponse.v) does not match the HMAC the client computed from its own server key. A signature mismatch means the password is wrong OR the server is not who it claims to be (the SCRAM server proof verifies both).

Source

Thrown at src/cmap/auth/scram.ts:189

  const payloadString = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);
  const authMessage = [firstMessage, payloadString, withoutProof].join(',');

  const clientSignature = await HMAC(cryptoMethod, storedKey, authMessage);
  const clientProof = `p=${xor(clientKey, clientSignature)}`;
  const clientFinal = [withoutProof, clientProof].join(',');

  const serverSignature = await HMAC(cryptoMethod, serverKey, authMessage);
  const saslContinueCmd = {
    saslContinue: 1,
    conversationId: response.conversationId,
    payload: new Binary(ByteUtils.fromUTF8(clientFinal))
  };

  const r = await connection.command(ns(`${db}.$cmd`), saslContinueCmd, undefined);
  const parsedResponse = parsePayload(r.payload);

  if (!compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature)) {
    throw new MongoRuntimeError('Server returned an invalid signature');
  }

  if (r.done !== false) {
    // If the server sends r.done === true we can save one RTT
    return;
  }

  const retrySaslContinueCmd = {
    saslContinue: 1,
    conversationId: r.conversationId,
    payload: ByteUtils.allocate(0)
  };

  await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);
}

function parsePayload(payload: Binary) {
  const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);

View on GitHub (pinned to 3366c21a63)

Solutions

  1. Double-check the password - test it with 'mongosh' using the same URI
  2. Verify the username is correct and exists in the configured authSource
  3. Confirm authSource matches where the user was created (admin vs application db)
  4. Reset the user's password server-side and update the client URI

Example fix

// before
const client = new MongoClient('mongodb://user:oldpass@host/?authSource=admin');
// after
const client = new MongoClient('mongodb://user:newpass@host/?authSource=admin');
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect();
  await client.db().command({ ping: 1 });
} catch (e) {
  if (e instanceof MongoRuntimeError && /invalid signature/i.test(e.message)) {
    // wrong password or wrong user - verify credentials with mongosh
  }
  throw e;
}

Prevention

When it happens

Trigger: Incorrect password supplied for the username; corrupted credentials during transit; a malicious server impersonating the real one without the correct shared secret; mismatched authSource causing auth against a different user store.

Common situations: Wrong password in the connection string; credentials rotated server-side but not in the client; typo in username leading to a different (existing) user whose password differs; copying a connection string between environments without updating the password.

Related errors


AI-assisted analysis of mongodb/node-mongodb-native@3366c21a63 (2026-08-04). Data as JSON: /data/errors/1cfea67daf0769d6.json. Report an issue: GitHub.