brianc/node-postgres · error · Error

SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be…

Error message

SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64

What it means

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.

Solutions

  1. Verify network integrity — check for corrupting proxies or intermediaries.
  2. Confirm the server is a standard PostgreSQL instance.
  3. Enable SSL/TLS to protect the authentication data stream.
  4. Test the connection with psql from the same environment to isolate server vs. client issues.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await client.connect()
} catch (err) {
  if (err.message.includes('server signature must be base64')) {
    throw new Error('SCRAM signature is not valid base64 — check for data corruption or non-conformant server')
  }
  throw err
}

Prevention

When it happens

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

Common situations: 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.

Related errors


AI-assisted analysis of brianc/node-postgres@ff9d775abd (2026-08-11). Data as JSON: /api/errors/837da76b8d8f91a5. Report an issue: GitHub.

Appendix: source

Thrown at packages/pg/lib/crypto/sasl.js:234

    nonce,
    salt,
    iteration,
  }
}

function parseServerFinalMessage(serverData) {
  const attrPairs = parseAttributePairs(serverData)
  const error = attrPairs.get('e')
  const serverSignature = attrPairs.get('v')

  if (error) {
    throw new Error(`SASL: SCRAM-SERVER-FINAL-MESSAGE: server returned error: "${error}"`)
  }

  if (!serverSignature) {
    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature is missing')
  } else if (!isBase64(serverSignature)) {
    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature must be base64')
  }
  return {
    serverSignature,
  }
}

function xorBuffers(a, b) {
  if (!Buffer.isBuffer(a)) {
    throw new TypeError('first argument must be a Buffer')
  }
  if (!Buffer.isBuffer(b)) {
    throw new TypeError('second argument must be a Buffer')
  }
  if (a.length !== b.length) {
    throw new Error('Buffer lengths must match')
  }
  if (a.length === 0) {
    throw new Error('Buffers cannot be empty')

View on GitHub (pinned to ff9d775abd)