Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string #2757

Open
yuneda opened this issue Jun 7, 2022 · 19 comments
Open

Comments

@yuneda
Copy link

yuneda commented Jun 7, 2022

https://github.com/brianc/node-postgres/blob/master/packages/pg/lib/sasl.js
Line 23 to 25

@yuneda
Copy link
Author

yuneda commented Jun 7, 2022

  if (typeof password !== 'string') {
    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')
  }

@sehrope
Copy link
Contributor

sehrope commented Jun 7, 2022

Is there a question or issue? That check was added to the SASL code to provide the end user with a more informative error message rather than just failing due to the password being null / undefined.

@yuneda
Copy link
Author

yuneda commented Jun 7, 2022

I'm using jest and supertest for testing my express APIs with Postgre.
The error comes from my code below.

const app = require('../../app');
const request = require('supertest');
let agent = request.agent(app);

describe('Cars', function () {
  it('Get all car', (done) => {
    agent
      .get('/v1/cars')
      .expect('Content-Type', /json/)
      .then((response) => {
        expect(response.status).toEqual(200);
      });
    done();
  });
});

@sehrope
Copy link
Contributor

sehrope commented Jun 7, 2022

You're probably running your tests without the database password available to the test environment.

If you're having an actual issue with this library then provide a self contained example that reproduces it.

@alexianaa
Copy link

alexianaa commented Jul 20, 2022

I changed the password using:

$ sudo passwd postgres
new password:
password again:
$ su postgres

remember change the password at the file

@ghost
Copy link

ghost commented Jul 31, 2022

I don't know if the root cause is the same, but I can reliably reproduce this just by trying to connect to a database that isn't password-protected, which I believe ought to be possible (even if not advisable in production, obviously...)

new pg.Pool({
  connectionString: "postgres://username@localhost/dbname"
});

@sehrope
Copy link
Contributor

sehrope commented Aug 1, 2022

@Quintinius The "localhost" in that connection URI would connect over TCP, not a unix socket. Check your pg_hba to see if TCP connections are requiring SASL. It's probably only local unix socket connections that are password-less.

@bever1337
Copy link

bever1337 commented Aug 20, 2022

Here is a minimal reproduction:

# .env
PGDATABASE=blahblahblah
PGUSER=blahblahblah
{
  "name": "example reproduction",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "UNLICENSED",
  "dependencies": {
    "dotenv": "^16.0.1",
    "pg": "^8.7.3"
  }
}
const { Pool } = require('pg');
const  dotenv = require('dotenv');

dotenv.config();

async function main() {
  const pool = new Pool();
  const client = await pool.connect();
  client.release();
}

main();

Environment requirements are a database, a database user, and no required database password. Observe that the script exits after some time in v16.14.0 but throws the SASL error in v18.7.0. Guarantee the password parameter is an empty string in both input options and .env files and observe no change in behavior.

I am assuming there is a breaking change with a NodeJS data type.

I've been using a database without a password for local testing and development. The database is only available on the local machine. node-postgres has been working fine in another project. I upgraded the node runtime to v18 so I could make use of experimental global Request/Response interfaces and can no longer use pg. Bummer! I hope this helps.

When I add a password blahblahblah to user blahblahblah, the script works as-expected regardless of node runtime.

@Vlado-99
Copy link

Vlado-99 commented Sep 15, 2022

Is there a question or issue?

It is not possible to connect to database using connectionString anymore, if the database account is without password.
This is a breaking change, issue.

The problem - in my specific case - was outside this library. Sorry for noise.

@rhewy
Copy link

rhewy commented Nov 20, 2022

If a blank password is sent to the postgreSQL server then and error is thrown

throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string')

The error is very special; not caught by .catch on the client promise and not caught with a try catch

@rhewy
Copy link

rhewy commented Nov 20, 2022

Port can be blank --> defaults to 5432
Username can be blank --> defaults to the OS username
Host can be blank --> defaults to localhost

Just a blank password caused the problem

@rhewy
Copy link

rhewy commented Nov 20, 2022

This seemed to help; if the password is blank/empty set it to a single space

    var connConfig = {
        host: req.body.host,
        port: req.body.port,
        database: req.body.database,
        user: req.body.username,
        password: req.body.password
    };

    connConfig.password = connConfig.password.length == 0 ? " " : connConfig.password

   

@rhewy
Copy link

rhewy commented Nov 20, 2022

Speculation

Could be that a blank password causes a syntax error in the JavaScript code; could be uncatchable.

@Nikire
Copy link

Nikire commented Dec 25, 2022

Hi ! just want to share my solution, I was getting this error by badly importing some models and using them before I sync the server
The way I was importing the models :
const { models: { User, Post } } = require('../sequelize');

The problem was that I was importing the models and using it directly in a helpers/utils/functions file,
and then I solve it by passing the models through parameters :

async findPostAndUser(postId, userId, Post, User) {
const post = await Post.findOne({ where: { id: { [Op.eq]: postId } } });
const user = await User.findOne({ where: { id: { [Op.eq]: userId } } });
return [post, user];}

@jgoux
Copy link

jgoux commented Jan 19, 2023

We are hitting this issue too, any password-protected database receiving a connection string with an empty password is raising this error.

I absolutely have no clue why we can't catch this error, this is actually my main issue. Does anyone know why it's not possible to catch this one? 😅

@rhewy
Copy link

rhewy commented Jan 19, 2023

I absolutely have no clue why we can't catch this error,

To use a Java analogy, it would be a difference between a compiler error versus a runtime error. The try catch does not get a chance to 'fire' as the JavaScript has syntax errors i.e. NOT compilable/runnable. Imagine a missing brace.

This next part is complete speculation, some regular expression strips quotes so that only the text of the password is sent to the database, however, if the password is blank then striping the quotes turns the password from a string to undefine which then causes a syntax error blowing up the code before the try catch can do its thing.

Or it could be something completely different.

For comic relief, I recommend watching this (so much applies):
https://youtu.be/Uo3cL4nrGOk

The line below might help

// ==================================================
// if the password is blank set it to a single space
// ==================================================
connConfig.password = connConfig.password.length == 0 ? " " : connConfig.password

@jean-pita
Copy link

jean-pita commented Dec 19, 2023

I'm using typeorm and I had to export an environment variable with the database connection string:

export DATABASE_URL=postgres://postgres:postgres@localhost:5432/default

@shuvo-halder

This comment was marked as duplicate.

@rhewy
Copy link

rhewy commented Dec 8, 2024

Your password is blank/null. Somewhere you need to set it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants