Create a Restful API in Flask with authentication required

Video thumbnail

Creating a Restful API in Flask is one of the simplest and most effective ways to connect applications and systems. In my experience, Flask offers the ideal flexibility for building clean, secure, and easy-to-maintain web services. Throughout this guide, I show you how I do it step-by-step, from installation to authentication, including real code and practical tips that have worked for me in real projects.

We left off with how we can use Flask-SocketIO to create real-time applications with Python.

What is a RESTful API and why use Flask to create one

A RESTful API follows the principle that every resource in the system is represented by a unique URL and is manipulated through the standard HTTP methods:

  • GET: retrieve information.
  • POST: create new resources.
  • PUT/PATCH: update existing data.
  • DELETE: delete records.

A Rest API is a function-based structure that is widely used today to communicate systems or different applications, each resource we can create are simply functions that are ultimately translated via URLs that are consumed via HTTP and its methods:

Therefore, depending on the HTTP method, we can give a different response, always respecting the purpose of each type of HTTP request.

Flask is perfect for this because it allows you to build a lightweight API without excessive configuration. With just a few lines of code, you already have functioning endpoints, and with the Flask-Restful package, you can structure everything into well-organized classes.

Differences between REST and RESTful

"REST" is the architectural style, while "RESTful" refers to the practical implementation that complies with those principles: well-defined resources, communication via HTTP, and JSON format.

Advantages of using Flask compared to other frameworks

  • Lightness: ideal for microservices or specific APIs.
  • Extensibility: compatible with extensions such as Flask-Restful, Flask-HTTPAuth, SQLAlchemy.
  • Short learning curve: it's quickly mastered if you already know Python.

Preparing the work environment: Necessary tools

So, to work with this package, the first thing we need is our Flask application and then install the package for Restful using:

$ pip install flask-restful

Base project structure:

my_app/
│
├── app.py
├── models.py
├── rest/
│   ├── controllers.py
│   └── __init__.py
└── auth/
   ├── model/
   │   └── user.py

Now we are ready to use this package.

Best practices and getting to know flask restful

The key to a good API is not just that it works, but that it is predictable and consistent.
Some common mistakes to avoid:

  • Not validating user input before operating with the database.
  • Not returning clear messages for 400 or 404 errors.
  • Not documenting the endpoints or their parameters.

I always recommend testing endpoints with Postman or CURL and documenting using Swagger or OpenAPI if the API will grow.

Automatic object to dictionary conversion

Another very interesting element is that we have a decorator called marshal_with that allows us to indicate immediately which fields we want to return from the model we are working with every time we return the object; for this, we first have to define the structure that holds the aforementioned:

resource_fields = {
   'id': fields.Integer,
   'name' : fields.String
}

This decorator also optionally receives the wrapper of the json it will return, which we can configure using the envelope.

Implementing the complete CRUD

How HTTP methods work

Each HTTP method has a specific purpose and should always be respected. In my projects, maintaining this convention has helped me a lot because it simplifies code maintenance and documentation.

Creation of Resource classes

With Flask-Restful, each Resource class represents a set of operations on a resource.
I like to separate the classes that don't need an ID (for listing or creating) from those that do (for reading, updating, or deleting).

We are going to create a couple of classes for each entity that we want to make manageable, that is, perform CRUD on a model, which, remember, is our connection to a table in the database.

Before starting

Remember that here we are not going to deal with how to work with SQLAlchemy to make connections to our database with our Flask project; we are simply going to perform the CRUD-type queries to operate the database.

You are probably wondering why we need two classes and not just one; the answer is due to the definition of the routes, so we will have:

  1. One class for methods that do NOT require a pk or id to operate
  2. One class for methods that DO require a pk or id to operate

Therefore, the routes and configuration we make look like this:

from flask_restful import Api
from proyect_app.rest.controllers import BookApi, BookApiId
 
api = Api(app) #, decorators=[csrf.exempt]
api.add_resource(BookApi, '/api/book')
api.add_resource(BookApiId, '/api/book/<string:id>')

So, we are going to create one to work without IDs or PKs; as you might guess, this would be for the Post method, to create a record, and for get, to get ALL records.

We are going to work with the following model:

class Category(db.Model):
   __tablename__ = 'categories'
   id = db.Column(db.Integer, primary_key=True)
   name = db.Column(db.String(255))

Additional functionalities over our package

Our package for achieving a Restful API brings several interesting elements that make our lives much easier for creating these types of CRUD APIs.

POST Method: create new resources

@marshal_with(resource_fields, envelope="categoria")
def post(self):
    parser = reqparse.RequestParser()
    parser.add_argument('name', required=True, help="No mandaste el nombre")
    args = parser.parse_args()
    c = Category(args['name'])
    db.session.add(c)
    db.session.commit()

Here we are going to work to create a record, so let's create another class that WILL work with IDs:

GET Method: retrieve all records

@marshal_with(resource_fields, envelope="categorias")
def get(self):
    return Category.query.all()

Here we are going to return a record by its identifier:

PATCH/PUT Methods: update data

@marshal_with(resource_fields, envelope="categoria")
def patch(self, id):
    parser = reqparse.RequestParser()
    parser.add_argument('name', required=True)
    args = parser.parse_args()
    c = Category.query.get_or_404(id)
    c.name = args['name']
    db.session.commit()
    return c

DELETE Method: delete a record

def delete(self, id):
    c = Category.query.get_or_404(id)
    db.session.delete(c)
    db.session.commit()
    return {'msj': 'ok'}

Finally, all the code for both classes:

from flask import request
from flask_restful import Resource, abort, reqparse, fields, marshal_with
from flask_httpauth import HTTPBasicAuth
 
from my_app.product.models import Category
from my_app.auth.model.user import User
from my_app import user_manager
from my_app import db
 
resource_fields = {
   'id': fields.Integer,
   'name' : fields.String
}
 
auth = HTTPBasicAuth()
 
@auth.verify_password
def verify_password(username, password):
   user = User.query.filter_by(username=username).first()
 
   if not user or not user_manager.verify_password(password_hash=user.password, password=password):
       return False
   return True
 
class Base:
   def category_to_json(self,category):
       return {
           'id': category.id,
           'name': category.name,
       }
 
   def abort_if_doesnt_exist(self, id, json=True):
       category = Category.query.get(id)
       if category is None:
           abort(404, message="Categoría {} no existe".format(id))
       if json:
           return self.category_to_json(category)
 
       return category
 
class CategoryRestFul(Resource,Base):
 
   @auth.login_required
   @marshal_with(resource_fields, envelope="categoria")
   def get(self, id):
       return self.abort_if_doesnt_exist(id,False)
 
   @marshal_with(resource_fields, envelope="categoria")
   def patch(self, id):
 
       parser = reqparse.RequestParser()
       parser.add_argument('name', required=True, help="No mandastes el nombre")       args = parser.parse_args()
 
       c = self.abort_if_doesnt_exist(id, False)
 
       c.name = args['name'] #request.form
 
       db.session.add(c)
       db.session.commit()
 
       return self.abort_if_doesnt_exist(c.id,False)
 
   def delete(self, id):
 
       c = self.abort_if_doesnt_exist(id, False)
 
       db.session.delete(c)
       db.session.commit()
 
       return {'msj':'ok'}
 
 
class CategoryRestFulList(Resource,Base):
 
   @marshal_with(resource_fields, envelope="categorias")
   def get(self):
       return Category.query.all()
 
   @marshal_with(resource_fields, envelope="categoria")
   def post(self):
      
       parser = reqparse.RequestParser()
       parser.add_argument('name',required=True, help="No mandastes el nombre")
       args = parser.parse_args()
 
       c = Category(args['name'])
       db.session.add(c)
       db.session.commit()
 
       return c
 
class CategoryRestFulListSearch(Resource,Base):
 
   @marshal_with(resource_fields, envelope="categoria")
   def get(self):
 
       parser = reqparse.RequestParser()
       parser.add_argument('search',required=True, help="Tienes que especificar la busqueda")
       args = parser.parse_args()
 
       return Category.query.filter(Category.name.like('%{0}%'.format(args['search']))).all()

Other functionalities

We are going to create an auxiliary class that will allow us to add some additional functionalities over the rest-type classes; for example, login protection.

And here we define our methods

@marshal_with(resource_fields, envelope="categorias")
def get(self):
  return Category.query.all()

With this function, we are going to get all the records from our database:

Points to consider

As you can see, the operations we perform in the Rest API are nothing strange, some validations, operations on the database, and little else, but as you can see, we have a very practical mechanism to manipulate or obtain data from our user; the data passed to us via a form, an axios request, or any API you use to send data via HTTP, we obtain them using the RequestParser class; the great thing about this is that we can define efficient validations in the add_argument function and therefore we can be 100 percent sure that the data we are working with is valid.

Security and Required Authentication in the Restful with Flask

As you can see, we are using a function that ultimately works as a decorator on our Rest resources to perform the required authentication on our Rest API; this is a third-party package that you can adapt to other types of services but that works quite well with Flask Restful; we simply have to define a base function in which we perform the operations on our user model, whatever you want to verify in the required authentication phase of the Rest API you can define it in that function.

In this example, we have a simple example in which we first search by username, and if it exists, we then verify the password, which is in hash format in the database; therefore, it is a function that is responsible for performing a manual login, and which we use perfectly in our Rest API as required authentication.

@auth.verify_password
def verify_password(username, password):
    user = User.query.filter_by(username=username).first()
    if not user or not user_manager.verify_password(password_hash=user.password, password=password):
        return False
    return True

Remember that to use this authentication package you have to install it with:

pip install Flask-HTTPAuth

Conclusion

In my experience developing RESTful APIs with Flask, I learned that using flask-restful greatly reduces the effort of keeping the code clean and modular. Separating classes based on whether they use an ID or not, validating input with reqparse, and protecting routes with HTTPAuth are practices that make the difference between a prototype and a production-ready API.

Frequently Asked Questions (FAQ)

What is the difference between Flask and Flask-Restful?
Flask is the base microframework; Flask-Restful adds a layer that facilitates the creation of structured APIs with resources and HTTP methods.

How can I protect my API with token authentication?
You can integrate Flask-JWT or Flask-JWT-Extended to handle JWT tokens instead of basic authentication.

Is Flask recommended for large projects?
Yes, but it requires modularization: splitting the app into blueprints and using a clear package architecture.

How do I test my API with Postman or cURL?
With Postman you can send requests to each endpoint; with CURL, use commands like curl -X GET http://localhost:5000/api/book.

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

 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.

Next step, learn how to configure CORS so you can connect an external application to the Rest API in Flask.

I agree to receive announcements of interest about this Blog.

We are going to learn how to easily create a Restful API in Flask using the package called flask_restful which, as its name suggests, allows us to easily create a CRUD Restful API.

| 👤 Andrés Cruz

🇪🇸 En español