How to enable authenticated MongoDB access for Flask-MongoEngine applications

After having a first look at MongoDB more than 5 years back, I told myself that I will use MongoDB to realise the next functionality of Techcoil.

With exposure to Python 3, Flask and MongoEngine in 2017, I had acquired the skills to build a microsite to recommend gift ideas. This microsite uses MongoDB to store the gift recommendation data.

With Flask and MongoEngine, development of this microsite did not take too much leisure time. With MongoDB not enforcing authentication, there were not much hindrance in setting up the development environment for this microsite.

However, this free-for-all mode of accessing MongoDB is not recommended for production environments. Without authentication, it is easier for ill-intentioned people to mess up the backend database.

To ensure that I have a go-to post for implementing authenticated access to MongoDB backed projects in the future, I document the steps needed for Flask-MongoEngine applications to access MongoDB instances with access control turned on.

Enabling authenticated access for MongoDB

To enable authenticated access for MongoDB, we will need to follow through a the following steps at the MongoDB server end:

  • An admin user account that can create new user accounts in MongoDB.
  • MongoDB instance running with access control.
  • A user account for our Flask + mongoengine application to interact with a database instance.

Creating the admin user account that can create new user accounts in MongoDB

With the free-for-all mode of MongoDB turned on, we first create the admin user account that will allow us to create new user accounts in MongoDB. The credentials for each user account will be kept in a MongoDB database instance. We typically refer to such database instance as the authentication database.

MongoDB recommends that we put such user credentials inside the "admin" database instance. Since it is an admin user account, we will give it the "userAdminAnyDatabase" role so that we can create other user accounts later.

To begin creating the admin user account, we use the MongoDB shell to connect to our MongoDB instance. The following command will connect the MongoDB shell to a MongoDB server instance listening on port 27017 locally.

mongo --port 27017

Once we got connected, we run the following commands to create the admin user:

use admin
db.createUser(
  {
    user: "myAdmin",
    pwd: "passwordForAdmin",
    roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  }
)

In the above set of commands, we first switch to the "admin" database and use the db.createUser function to create the user account.

We then feed in a JSON that describes the username, password and the role that the admin user will take.

Running MongoDB with access control

With the admin user created, the next step will be to make MongoDB run with access control.

To do so, we can either update our MongoDB start script to run mongod with the --auth flag:

mongod --auth --port 27017

Or add the following configurations to the configuration file that our MongoDB instance reads from:

security:
  authorization: "enabled"

If we had installed MongoDB on Ubuntu through the mongodb-org meta-package, we will find the configuration file at /etc/mongod.conf.

Using MongoDB shell to connect to a MongoDB instance running in authentication mode

Once our MongoDB instance runs with access control, we will then run the following command to use MongoDB shell to interact with it again:

mongo --port 27017 -u "myAdmin" -p --authenticationDatabase "admin"

This time round, we supplied the username of our admin user to the MongoDB shell. We also specify that we can MongoDB to check the supplied user credentials with the ones located inside the "admin" database instance. This command will prompt for the password of the admin user. Supply the password that you had created earlier.

Creating a user account for our Flask-MongoEngine application to interact with a database instance

Once we get into the MongoDB interactive shell successfully, we can then proceed with the creation of a user account that can only interact with the application database instance.

To do so, we run the following set of commands:

use admin
db.createUser(
  {
    user: "appUser",
    pwd: "passwordForAppUser",
    roles: [ { role: "readWrite", db: "app_db" } ]
  }
)

In the above commands, we first switched to the "admin" database instance. We then created a user "appUser" with the "readWrite" role on the "app_db" database instance.

Supplying the user account credentials to Flask-MongoEngine for interacting with the MongoDB database instance with access control

Once the MongoDB server side configurations are done, we can then include the following configurations to our Flask-MongoEngine application:

from flask import Flask
from flask_mongoengine import MongoEngine

app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {
    'db': 'app_db',
    'host': 'localhost',
    'port': 27017,
    'username': 'appUser',
    'password': 'passwordForAppUser',
    'authentication_source': 'admin'
}

db = MongoEngine(app)

In the above codes, we specify the settings that we want Flask-MongoEngine to use for connecting to our MongoDB database instance with the user account that we had created earlier. We specify:

  • the database instance via the 'db' key.
  • the address of our MongoDB server via the 'host' key.
  • the port where our MongoDB server listens to via the 'port' key.
  • the username of our user account via the 'username' key.
  • the password of our user account via the 'password' key.
  • the MonogDB instance where our user account resides in via the 'authentication_source' key.

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.