{"id":"1cfea67daf0769d6","repo":"mongodb/node-mongodb-native","slug":"server-returned-an-invalid-signature","errorCode":null,"errorMessage":"Server returned an invalid signature","messagePattern":"Server returned an invalid signature","errorType":"exception","errorClass":"MongoRuntimeError","httpStatus":null,"severity":"critical","filePath":"src/cmap/auth/scram.ts","lineNumber":189,"sourceCode":"  const payloadString = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);\n  const authMessage = [firstMessage, payloadString, withoutProof].join(',');\n\n  const clientSignature = await HMAC(cryptoMethod, storedKey, authMessage);\n  const clientProof = `p=${xor(clientKey, clientSignature)}`;\n  const clientFinal = [withoutProof, clientProof].join(',');\n\n  const serverSignature = await HMAC(cryptoMethod, serverKey, authMessage);\n  const saslContinueCmd = {\n    saslContinue: 1,\n    conversationId: response.conversationId,\n    payload: new Binary(ByteUtils.fromUTF8(clientFinal))\n  };\n\n  const r = await connection.command(ns(`${db}.$cmd`), saslContinueCmd, undefined);\n  const parsedResponse = parsePayload(r.payload);\n\n  if (!compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature)) {\n    throw new MongoRuntimeError('Server returned an invalid signature');\n  }\n\n  if (r.done !== false) {\n    // If the server sends r.done === true we can save one RTT\n    return;\n  }\n\n  const retrySaslContinueCmd = {\n    saslContinue: 1,\n    conversationId: r.conversationId,\n    payload: ByteUtils.allocate(0)\n  };\n\n  await connection.command(ns(`${db}.$cmd`), retrySaslContinueCmd, undefined);\n}\n\nfunction parsePayload(payload: Binary) {\n  const payloadStr = ByteUtils.toUTF8(payload.buffer, 0, payload.position, false);","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cmap/auth/scram.ts#L171-L207","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Double-check the password - test it with 'mongosh' using the same URI","Verify the username is correct and exists in the configured authSource","Confirm authSource matches where the user was created (admin vs application db)","Reset the user's password server-side and update the client URI"],"exampleFix":"// before\nconst client = new MongoClient('mongodb://user:oldpass@host/?authSource=admin');\n// after\nconst client = new MongoClient('mongodb://user:newpass@host/?authSource=admin');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n  await client.db().command({ ping: 1 });\n} catch (e) {\n  if (e instanceof MongoRuntimeError && /invalid signature/i.test(e.message)) {\n    // wrong password or wrong user - verify credentials with mongosh\n  }\n  throw e;\n}","preventionTips":["Verify credentials with mongosh using the identical URI before coding","Confirm authSource matches the database where the user was created","After server-side password rotations, update the client immediately","Encode special characters in the password via encodeURIComponent"],"tags":["auth","scram","credentials","security","signature"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}