EventGet 50% off your ticket to MongoDB.local NYC on May 2. Use code Web50!Learn more >>
MongoDB Developer
Python
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Pythonchevron-right

Adding Authentication to Your FARM Stack App

Aaron Bassett, Mark Smith7 min read • Published Feb 12, 2022 • Updated Apr 02, 2024
FastApiJavaScriptPython
Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
If you have not read my Introduction to FARM stack tutorial, I would urge you to do that now and then come back. This guide assumes you have already read and understood the previous article so some things might be confusing or opaque if you have not.
An important part of many web applications is user management, which can be complex with lots of different scenarios to cover: registration, logging in, logging out, password resets, protected routes, and so on. In this tutorial, we will look at how you can integrate the FastAPI Users package into your FARM stack.

Prerequisites

  • Python 3.9.0
  • A MongoDB Atlas cluster. Follow the "Get Started with Atlas" guide to create your account and MongoDB cluster. Keep a note of your database username, password, and connection string as you will need those later.
  • A MongoDB Realm App connected to your cluster. Follow the "Create a Realm App (Realm UI)" guide and make a note of your Realm App ID.

Getting Started

Once you have cloned the repository, you will need to install the dependencies. I always recommend that you install all Python dependencies in a virtualenv for the project. Before running pip, ensure your virtualenv is active. The requirements.txt file is within the back end folder.
It may take a few moments to download and install your dependencies. This is normal, especially if you have not installed a particular package before.
You'll need two new configuration values for this tutorial. To get them, log into Atlas and create a new Realm App by selecting the Realm tab at the top of the page, and then clicking on "Create a New App" on the top-right of the page.
Create a new Realm App
Configure the Realm app to connect to your existing cluster:
Configure a new Realm App
You should see your Realm app's ID at the top of the page. Copy it and keep it somewhere safe. It will be used for your application's REALM_APP_ID value.
Get your app's Id
Click on the "Authentication" option on the left-hand side of the page. Then select the "Edit" button next to "Custom JWT Authentication". Ensure the first option, "Provider Enabled" is set to "On". Check that the Signing Algorithm is set to "HS256". Now you need to create a signing key, which is just a set of 32 random bytes. Fortunately, Python has a quick way to securely create random bytes! In your console, run the following:
Running that line of code will print out some random characters to the console. Type "signing_key" into the "Signing Key (Secret Name)" text box and then click "Create 'signing_key'" in the menu that appears underneath. A new text box will appear for the actual key bytes. Paste in the random bytes you generated above. Keep the random bytes safe for the moment. You'll need them for your application's "JWT_SECRET_KEY" configuration value.
Configure a JWT signing key.
Now you have all your configuration values, you need to set the following environment variables (make sure that you substitute your actual credentials).
Set these values appropriately for your environment, ensuring that REALM_APP_ID and JWT_SECRET_KEY use the values from above. Remember, anytime you start a new terminal session, you will need to set these environment variables again. I use direnv to make this process easier. Storing and loading these values from a .env file is another popular alternative.
The final step is to start your FastAPI server.
Once the application has started, you can view it in your browser at http://127.0.0.1:8000/docs.
Screenshot of FARM app Swagger UI
You may notice that we now have a lot more endpoints than we did in the FARM stack Intro. These routes are all provided by the FastAPI Users package. I have also updated the todo app routes so that they are protected. This means that you can no longer access these routes, unless you are logged in.
If you try to access the List Tasks route, for example, it will fail with a 401 Unauthorized error. In order to access any of the todo app routes, we need to first register as a new user and then authenticate. Try this now. Use the /auth/register and /auth/jwt/login routes to create and authenticate as a new user. Once you are successfully logged in, try accessing the List Tasks route again. It should now grant you access and return an HTTP status of 200. Use the Atlas UI to check the new farmstack.users collection and you'll see that there's now a document for your new user.

Integrating FastAPI Users

The routes and models for our users are within the /backend/apps/user folder. Lets walk through what it contains.

The User Models

The FastAPI Users package includes some basic User mixins with the following attributes:
  • id (UUID4) – Unique identifier of the user. Default to a UUID4.
  • email (str) – Email of the user. Validated by email-validator.
  • is_active (bool) – Whether or not the user is active. If not, login and forgot password requests will be denied. Default to True.
  • is_superuser (bool) – Whether or not the user is a superuser. Useful to implement administration logic. Default to False.
You can use these as-is for your User models, or extend them with whatever additional properties you require. I'm using them as-is for this example.

The User Routers

The FastAPI Users routes can be broken down into four sections:
  • Registration
  • Authentication
  • Password Reset
  • User CRUD (Create, Read, Update, Delete)
You can read a detailed description of each of the routes in the FastAPI Users' documentation, but there are a few interesting things to note in this code.

The on_after Functions

These functions are called after a new user registers and after the forgotten password endpoint is triggered.
The on_after_register is a convenience function allowing you to send a welcome email, add the user to your CRM, notify a Slack channel, and so on.
The on_after_forgot_password is where you would send the password reset token to the user, most likely via email. The FastAPI Users package does not send the token to the user for you. You must do that here yourself.

The get_users_router Wrapper

In order to create our routes we need access to the fastapi_users object, which is part of our app object. Because app is defined in main.py, and main.py imports these routers, we wrap them within a get_users_router function to avoid creating a cyclic import.

Creating a Custom Realm JWT

Currently, Realm's user management functionality is only supported in the various JavaScript SDKs. However, Realm does support custom JWTs for authentication, allowing you to use the over the wire protocol support in the Python drivers to interact with some Realm services.
The available Realm services, as well as how you would interact with them via the Python driver, are out of scope for this tutorial, but you can read more in the documentation for Users & Authentication, Custom JWT Authentication, and MongoDB Wire Protocol.
Realm expects the custom JWT tokens to be structured in a certain way. To ensure the JWT tokens we generate with FastAPI Users are structured correctly, within backend/apps/user/auth.py we define MongoDBRealmJWTAuthentication which inherits from the FastAPI Users' CookieAuthentication class.
Most of the authentication code stays the same. However we define a new _generate_token method which includes the additional data Realm expects.

Protecting the Todo App Routes

Now we have our user models, routers, and JWT token ready, we can modify the todo routes to restrict access only to authenticated and active users.
The todo app routers are defined in backend/apps/todo/routers.py and are almost identical to those found in the Introducing FARM Stack tutorial, with one addition. Each router now depends upon app.fastapi_users.get_current_active_user.
Because we have declared this as a dependency, if an unauthenticated or inactive user attempts to access any of these URLs, they will be denied. This does mean, however, that our todo app routers now must also have access to the app object, so as we did with the user routers we wrap it in a function to avoid cyclic imports.

Creating Our FastAPI App and Including the Routers

The FastAPI app is defined within backend/main.py. This is the entry point to our FastAPI server and has been quite heavily modified from the example in the previous FARM stack tutorial, so let's go through it section by section.
This function is called whenever our FastAPI application starts. Here, we connect to our MongoDB database, configure FastAPI Users, and include our routers. Your application won't start receiving requests until this event handler has completed.
The shutdown event handler does not change. It is still responsible for closing the connection to our database.

Wrapping Up

In this tutorial we have covered one of the ways you can add user authentication to your FARM stack application. There are several other packages available which you might also want to try. You can find several of them in the awesome FastAPI list.
Or, for a more in-depth look at the FastAPI Users package, please check their documentation.
If you have questions, please head to our developer community website where the MongoDB engineers and the MongoDB community will help you build your next big idea with MongoDB.

Facebook Icontwitter iconlinkedin icon
Rate this tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Building a Real-Time, Dynamic Seller Dashboard on MongoDB


Apr 02, 2024 | 7 min read
Quickstart

Getting Started with MongoDB and FastAPI


Mar 11, 2024 | 7 min read
Tutorial

How to Leverage an Event-Driven Architecture with MongoDB and Databricks


Jul 13, 2023 | 9 min read
Tutorial

Boosting AI: Build Your Chatbot Over Your Data With MongoDB Atlas Vector Search and LangChain Templates Using the RAG Pattern


Jan 16, 2024 | 7 min read
Table of Contents