{"record":{"id":"837da76b8d8f91a5","repo":"brianc/node-postgres","slug":"sasl-scram-server-final-message-server-signature-837da7","errorCode":null,"errorMessage":"SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64","messagePattern":"SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/pg/lib/crypto/sasl.js","lineNumber":234,"sourceCode":"    nonce,\n    salt,\n    iteration,\n  }\n}\n\nfunction parseServerFinalMessage(serverData) {\n  const attrPairs = parseAttributePairs(serverData)\n  const error = attrPairs.get('e')\n  const serverSignature = attrPairs.get('v')\n\n  if (error) {\n    throw new Error(`SASL: SCRAM-SERVER-FINAL-MESSAGE: server returned error: \"${error}\"`)\n  }\n\n  if (!serverSignature) {\n    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing')\n  } else if (!isBase64(serverSignature)) {\n    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64')\n  }\n  return {\n    serverSignature,\n  }\n}\n\nfunction xorBuffers(a, b) {\n  if (!Buffer.isBuffer(a)) {\n    throw new TypeError('first argument must be a Buffer')\n  }\n  if (!Buffer.isBuffer(b)) {\n    throw new TypeError('second argument must be a Buffer')\n  }\n  if (a.length !== b.length) {\n    throw new Error('Buffer lengths must match')\n  }\n  if (a.length === 0) {\n    throw new Error('Buffers cannot be empty')","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/brianc/node-postgres/blob/ff9d775abd12f29dd6df03945253b54eabbb29f2/packages/pg/lib/crypto/sasl.js#L216-L252","documentation":"Thrown by parseServerFinalMessage() when the server's signature verifier (v= attribute) fails the isBase64() regex check. The verifier must be valid standard base64 so the client can decode and compare it against the locally computed signature. Invalid base64 means the comparison cannot proceed.","triggerScenarios":"At sasl.js:233-234, isBase64(serverSignature) returns false. The v= attribute value does not match the base64 regex — it contains invalid characters, incorrect padding, or an invalid length.","commonSituations":"Data corruption in transit altering the signature bytes; an encoding mismatch (e.g., URL-safe base64); a non-conformant server sending the signature in a non-standard format; a proxy re-encoding or mangling the authentication stream.","solutions":["Verify network integrity — check for corrupting proxies or intermediaries.","Confirm the server is a standard PostgreSQL instance.","Enable SSL/TLS to protect the authentication data stream.","Test the connection with psql from the same environment to isolate server vs. client issues."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await client.connect()\n} catch (err) {\n  if (err.message.includes('server signature must be base64')) {\n    throw new Error('SCRAM signature is not valid base64 — check for data corruption or non-conformant server')\n  }\n  throw err\n}","preventionTips":["Verify network integrity — check for corrupting proxies or encoding issues.","Confirm the server is a standard PostgreSQL instance.","Enable SSL/TLS to protect authentication data.","Test with psql from the same environment to isolate the source."],"tags":["authentication","sasl","scram","protocol-error","base64","data-integrity"],"backgroundTag":null,"analyzedSha":"ff9d775abd12f29dd6df03945253b54eabbb29f2","analyzedAt":"2026-08-11T15:33:59.644Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}