Generate and grant credentials for MongoDB databases

mongodb pymongo authentication authorization, authentication, authorization, database-management, mongodb, pymongo, python
pip install mongogrant==0.3.1


Quickstart for users

So, your friendly neighborhood mongogranter says you know have access to a database through your email address. What now? First, install mongogrant:

pip install mongogrant

Next, request a token link to be sent to your email:

mgrant init \

Click the link in your email to prove you're you, copy the fetch token from the loaded page, and then run:

mgrant settoken wh054900d70k3ny35y0u423

Finally, get credentials for your database. Here, Marie is asking mongogrant to print out db.json and my_launchpad.yaml starter files for FireWorks and atomate:

mgrant db fw_mc_polonium \
  --role readWrite \

About mongogrant

Mongogrant is a utility to grant username and password credentials for read and readWrite roles on various databases on various hosts to owners of email addresses.

A server administrator has fine-grained control via allow/deny rules for granting tokens and credentials. People request an email that contains a one-time link. That link gives a user a fetch token. All tokens expire and expiration time is customizable. People then use the mongogrant client to make requests like

from mongogrant.client import Client

# config file on disk has tokens and host/db aliases
# `Client()` with no args looks to
# ~/.mongogrant.json for config
client = Client()

# No config yet? Set one up with at least one remote for fetching credentials
# See below for how to obtain <FETCH_TOKEN> for a given <ENDPOINT>.
client.set_remote("", "<FETCH_TOKEN>")

# Set some aliases if you'd like:
client.set_alias("dev", "", "host")
client.set_alias("prod", "", "host")
client.set_alias("fireworks", "fw_dw_phonons", "db")

# pymongo.database.Database with read role
source_db = client.db("ro:dev/fireworks")
# readWrite role: config stores "prod" host alias and "fireworks" db alias
target_db = client.db("rw:prod/fireworks")

# ...Do database stuff!

One can also go entirely through a running app's API:

> # Using the HTTPie command line HTTP client (
> # Install via `{brew,apt-get,pip,...} install httpie`
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 59
Content-Type: application/json
Date: Thu, 17 May 2018 18:05:30 GMT
Server: nginx/1.10.3

    "msg": "Sent link to <YOUR_EMAIL> to retrieve token."

HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Thu, 17 May 2018 18:06:17 GMT
Server: nginx/1.10.3
Transfer-Encoding: chunked

Fetch token: <FETCH_TOKEN> (expires 2018-06-19 18:05:30.508000 UTC)

> # end-of-line "\" below only necessary if command spans two lines.
> http --form POST<FETCH_TOKEN> \
>   role=readWrite db=dw_phonons
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 108
Content-Type: application/json
Date: Thu, 17 May 2018 18:11:22 GMT
Server: nginx/1.10.3

    "password": "<PASSWORD>",
    "username": "dwinston_lbl.gov_readWrite"


You can run a "server" on your laptop in a Jupyer notebook and manage allow/deny rules, grant / revoke grants of credentials, etc. A small Flask app is included as an example for deploying a server to which clients can connect to obtain tokens and credentials.

Set up a server

from mongogrant.config import Config
from mongogrant.server import Server, check, path, seed, Mailgun

server = Server(Config(check=check, path=path, seed=seed()))
server.set_mailer(Mailgun, dict(

Appointing others to set allow/deny rules

A mongogrant server admin can add "ruler" users who can set allow/deny rules for users via the mgrant CLI. An admin sets a ruler document in the server.mgdb collection, e.g.

    {"email": ""},
        "email": "",
        "hosts": [""],
        "dbs": ["mp_", "fw_"],
        "emails": [""],
        "which": ["allow"]

Allows user to set allow rules for any user with an "" email address on the Mongo host "" for any database name prefixed with "mp_" or "fw_". Any field in a ruler document can be set to "all" rather than an array.