Rest Api in Flask with JSON Web Token in MySQL or MongoDB

Video thumbnail

Protecting a REST API with Json Web Tokens (JWT) in Flask is one of the most practical and secure ways to handle authentication without relying on sessions. In this guide, I show you how to implement JWT in Flask from scratch, also integrating FlaskUser and MongoDB, just as I have done in my own projects.

Json Web Token (JWT) is just a string that we send from the browser or client to our server in the request header; and this for the purpose of validating and verifying the client; of course, the server is responsible for generating the JWT with some condition on an existing user, which is generally to check a user and password pair.

What is a Json Web Token (JWT) and how does it work

A JWT is an encoded string used to verify a client's identity to the server. Instead of maintaining sessions, the client sends the token in the header of each HTTP request.

Structure of a JWT: Header, Payload, and Signature

The token is composed of three parts separated by dots:

header.payload.signature
  • Header: indicates the token type and encryption algorithm (e.g., HS256).
  • Payload: contains the user data or claims.
  • Signature: guarantees that the token has not been tampered with.

How to use a JWT token in a REST API

The flow is simple:

  • The client logs in and sends username + password.
  • The server validates the credentials and generates the token.
  • The client includes that token in the header of each request:
    • Authorization: Bearer <token>
  • Flask verifies the token's validity before allowing access to resources.

Advantages over traditional sessions

Scalable and no need to store sessions.

Compatible with microservices and SPA frontends.

Easy to revoke or expire.

Requirements

We are going to develop in several technologies as you can see, but to make a brief summary, you will need:

In this post, we are going to learn how to protect a Rest API created with the FlaskRestFul package with Json Web Token, the famous JWT, using the FlaskJWT package, employing Flask, of course; in addition to this, we are going to use the famous package called FlaskUser to manage the user's access credentials; that is, username and password.

Installation of dependencies

$ pip install flask flask-restful flask-jwt flask-user mongoengine

Creating the necessary methods to work with Flask JWT

In this section, we will see what we need to configure to use Flask JWT in our Flask project; of course, these are general or example configurations and developments that you can use in any schema; in our case, we are going to use the FlaskUser package to handle everything related to login; in this case, we are interested in the function to manage credentials, specifically the use of the password.

Implementing JWT authentication in Flask

Within your Flask project, configure the database and user manager:

from flask_user import UserManager
from flask_mongoengine import MongoEngine

app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {'db': 'demo_jwt'}
db = MongoEngine(app)
user_manager = UserManager(app, db, User)

I use MongoDB, but you can easily adapt to SQLAlchemy if you work with MySQL

We create the model for the user:

import mongoengine as models
from flask_user import UserMixin
import mongoengine as models
from flask_user import UserMixin
  
class User(models.Document, UserMixin):
   active = models.BooleanField(default=True)
 
   # User authentication information
   username = models.StringField(default='')
   password = models.StringField()
 
   # User information
   first_name = models.StringField(default='')
   last_name = models.StringField(default='')
 
   def __str__(self):
       return self.username
 
class UserBase(object):
   def __init__(self, id, username, password):
       self.id = str(id)
       self.username = username
       self.password = password
  
   def __str__(self):
     return f"User id: {self.id}"

You only need to create the UserBase class if you are going to use MongoDB to do the JSON parsing that is used internally by FlaskJWT; we simply use this class as an intermediary to return the authenticated user.

The identity and login or authentication functions in Flask JWT

To be able to use the FlaskJWT package, we have to create a couple of functions in its minimum configuration, the first to get the authenticated user given the identifier, called identity, and another function to handle the login, that is, compare the username and password; so:

from .models import User, UserBase
from proyect_app import user_manager
 
def autheticate(username, password):
   user = User.objects(username=username).first()
  
   if user_manager.verify_password(password,user):
       userBase = UserBase(user.id, user.username, user.password)
       return userBase
 
def identity(payload):
   user_id = payload['identity']
   user = User.objects(id=user_id).first()
   return user

Authenticate function

For this function, which by default receives two parameters, the username and the password, we first search for the user and then verify the password, which is easy when using FlaskUser, and we can check the password using the function that FlaskUser provides us called verify_password; in the end, if everything is OK, we return the authenticated user.

Identity function

This function receives the payload, and we are interested in consuming the user ID, which we have as payload['identity'], and returning the user; it's that simple.

Global configurations:

At the level of our project, we have to create the configurations for JWT; it's the usual, and once the two previous functions are created, we import them and pass them as parameters to the corresponding class for Flask JWT:

# jwt
from proyect_app.user.jwt import autheticate, identity
jwt = JWT(app, autheticate, identity)

The imports:

from flask_user import UserManager from flask_jwt import JWT

And we configure our UserManager of our FlaskUser:

user_manager = UserManager(app, db, User)

Configure protection in MySQL or MongoDB

Now, depending on the database engine we are using, for example MongoDB with the connector we are using in our MongoDB with Flask and Django course:

db = MongoEngine(app)

or with SQLAlchemy that we can use, for example, MySQL:

db=SQLAlchemy(app)

Protect the Rest API in Flask

Finally, we protect the RestApi in FlaskRestFul; for example, we have a resource type class and we indicate the corresponding decorator:

class BookApi(Resource):
  decorators = [jwt_required()]

You can find the complete project of the Flask with MongoDB course at:

For the user model, remember that we are also using FlaskUser, the usual, at least the username and password: 

Necessary dependencies or installations

  1. https://pythonhosted.org/Flask-JWT/
  2. https://flask-user.readthedocs.io/en/latest/
  3. https://flask-restful.readthedocs.io/en/latest/
  4. http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/

Testing the API with Postman

Once JWT is configured, we can test it.

Obtaining the authentication token

Send a POST request to /auth with:

{ "username": "usuario", "password": "clave" }

Using the token in protected requests

Copy the generated token and place it in the headers:

Authorization: Bearer <token>

Possible responses

  • Code    Description
  • 200    Valid request, access allowed
  • 401    Invalid or missing token
  • 403    Expired token or unauthorized user

Postman was the most practical tool to verify the complete flow, especially when simulating authentication errors.

Solution to common errors with FlaskJWT and MongoDB

Some setbacks arise during implementation.

Error "ObjectId is not JSON serializable"

This problem appears when using MongoDB:

FlaskJWT tries to convert the user ID directly to JSON, which causes a failure.

Solution: return an instance of UserBase instead of the original MongoDB model.
This ensures that the ID is handled as a string.

Circular references when importing functions

Avoid importing authenticate and identity at the top of your __init__.py.
Do it after initializing app and db to prevent import errors.

Recommended modular structure

Divide your application into folders:

project_app/
├── user/
│    ├── models.py
│    ├── jwt.py
├── api/
│    ├── resources/
├── app.py


In my case, organizing the code this way greatly simplified testing and maintenance.

Good security and maintenance practices

Token expiration and renewal

Configure expiration:

app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=3600)

For renewals, implement a refresh endpoint if you use Flask-JWT-Extended.

Where to store JWTs

Avoid saving them in the browser's localStorage.

Use secure cookies (HttpOnly) or in-memory storage.

Flask-JWT vs Flask-JWT-Extended
Aspect    Flask-JWT    Flask-JWT-Extended
Simplicity    ✅ Easy to configure    ⚙️ More advanced options
Token renewal    ❌ No    ✅ Yes
Active support    Limited    Extensive
Recommended for    Simple APIs    Production projects

Conclusion

Implementing JWT in Flask allows for more modern and scalable authentication.
Combining FlaskUser with FlaskJWT allowed me to leverage the best of both worlds: robust password verification and token flexibility.

If you plan to work with MongoDB, remember to use a custom base class to avoid serialization errors and maintain the modular architecture from the start.

❓ Frequently Asked Questions (FAQ)

  • What is the best library for JWT in Flask?
    • Flask-JWT-Extended is the most complete currently, although Flask-JWT is still useful for small projects.
  • Can I use JWT without a database in Flask?
    • Yes, as long as the payload contains enough information to validate the user.
  • How to revoke a token in Flask?
    • Store the tokens in a revocation list (blacklist) and check each request.
  • What is the difference between authentication and authorization?
    • Authentication verifies who you are; authorization determines what you can do within the system.

I agree to receive announcements of interest about this Blog.

In this post we are going to know how we can work with Json Web Tokens in FlaskRestFul using MongoDB or MySQL with the FlaskUser package.

| 👤 Andrés Cruz

🇪🇸 En español