Iftieaq
Iftieaq

Reputation: 1964

Mongoose authentication failed with mongodb inside docker service

So, here is what I'm trying to do. I have created a MongoDB service using docker and trying to connect my NodeJs project to the database service using mongoose. Here is my docker-compose.yaml

version: '3'

services:

  mongodb:
    container_name: mongo_database
    image: mongo
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password
    networks:
      - mongo-compose-network
    ports:
      - '27017:27017'

  mongo-express:
    container_name: mongo_express
    image: mongo-express
    restart: unless-stopped
    depends_on:
      mongodb:
        condition: service_started
    networks:
      - mongo-compose-network
    environment:
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=password
      - ME_CONFIG_MONGODB_SERVER=mongodb
    ports:
      - '8081:8081'

networks:
  mongo-compose-network:
    driver: bridge

I have open the mongo-express panel and everything is working fine. Now, Here is my NodeJs app using MongoClient to connect to the database and insert a dummy record.

require('dotenv').config();

// required modules
const mongoose          = require("mongoose")
const MongoClient       = require('mongodb').MongoClient;

// database config
const db_name           = process.env.DB_NAME || "office"
const mongoUrl          = process.env.MONGO_URL || `mongodb://admin:password@localhost:27017`
const mongooseUrl       = process.env.MONGO_URL || `${mongoUrl}/${db_name}`


// database connection and sample document

const connectOptions    = {  useNewUrlParser: true,  useUnifiedTopology: true }

const document = {
    "name": "John Doe",
    "employee_id": Math.floor(Math.random() * 1000)
}

MongoClient.connect(mongoUrl, connectOptions).then((client)=> {

    client.db(db_name).collection("users").insertOne(document).then(()=> {
        console.log("Document Inserted")
        process.exit(1)
    })

}).catch((e) => {

    console.log(`Cannot connect to the database: ${e.message}`)
    process.exit(1)

})

Everything is still fine. The application has successfully inserted the record in the mongo database. However, things are not working when I tried to use Mongoose instead of MongoClient. Here is my code snippet for Mongoose.

require('dotenv').config();

// required modules
const mongoose          = require("mongoose")
const MongoClient       = require('mongodb').MongoClient;

// database config
const db_name           = process.env.DB_NAME || "office"
const mongoUrl          = process.env.MONGO_URL || `mongodb://admin:password@localhost:27017`
const mongooseUrl       = process.env.MONGO_URL || `${mongoUrl}/${db_name}`


// database connection and sample document

const connectOptions    = {  useNewUrlParser: true,  useUnifiedTopology: true }

const document = {
    "name": "John Doe",
    "employee_id": Math.floor(Math.random() * 1000)
}


mongoose.connect(mongooseUrl, connectOptions).then((connection) => {

    connection.collection('users').insert(document);

}).catch((e) => {

    console.log(`Cannot connect to the database: ${e.message}`)
    process.exit(1)

})

It's giving me the error Cannot connect to the database: Authentication failed.. Any ideas on how to resolve this issue?

Please note: I am running my node app in my physical machine, not inside a container using an image. I tried replacing the localhost:27017 with the service name such as mongodb://admin:password@mongodb/office but it doesn't work either. It returns the following error Cannot connect to the database: getaddrinfo EAI_AGAIN mongodb

Upvotes: 1

Views: 2070

Answers (1)

Alex Blex
Alex Blex

Reputation: 37048

TL;DR you need to specify authentication database in the mongooseUrl as ?authSource=admin or as {authSource:"admin"} in connectOptions.

Explanations

The docker image registers the MONGO_INITDB_ROOT_USERNAME user in the default authentication database admin.

This database is being used by default unless specified in the URI. The logic is unnecessarily complicated to my taste and the documentation isn't clear enough about it:

/defaultauthdb

Optional. The authentication database to use if the connection string includes username:password@ authentication credentials but the authSource option is unspecified.

If both authSource and defaultauthdb are unspecified, the client will attempt to authenticate the specified user to the admin database.

The missing bit is that the /defaultauthdb used to be /database - this version remains in mongoose documentation.

The parameter serves 2 purposes and this causes confusion. It specifies the default database where you store your collections and the default authentication database where Mongo looks-up users. Defaults can be overwritten by URI parameters:

authSource - The database to use when authenticating with user and pass. In MongoDB, users are scoped to a database. If you are getting an unexpected login failure, you may need to set this option.

Or connection options:

dbName - Specifies which database to connect to and overrides any database specified in the connection string. This is useful if you are unable to specify a default database in the connection string like with some

authSource - The database to use when authenticating with user and pass. In MongoDB, users are scoped to a database. If you are getting an unexpected login failure, you may need to set this option.

Upvotes: 7

Related Questions