Your Search Bar For Shrewd Tips

How To Add Jwt Authentication In Fastapi


How To Add JWT Authentication In FastAPI

FastAPI has rapidly become one of the most popular frameworks for building modern web APIs with Python. Its speed, simplicity, and automatic documentation make it an ideal choice for developers. One of the crucial aspects of building secure APIs is implementing authentication mechanisms. JSON Web Tokens (JWT) have gained widespread popularity for their stateless and secure approach to authentication. In this guide, we'll walk through how to add JWT authentication in FastAPI, enabling you to protect your endpoints effectively and securely.

Understanding JWT Authentication

Before diving into implementation, it's essential to understand what JWT authentication entails. JWT (JSON Web Token) is a compact, URL-safe token format that contains claims — pieces of information about the user or the context. These tokens are signed to ensure integrity and authenticity, usually with a secret or a public/private key pair.

JWTs are commonly used in stateless authentication systems because the server does not need to store session data; all the necessary information is encoded within the token itself. When a user logs in successfully, the server issues a JWT, which the client then includes in subsequent requests, typically in the Authorization header.

This approach simplifies scaling and reduces server-side storage needs, making JWT a compelling choice for RESTful APIs built with FastAPI.

Prerequisites

  • Python 3.7+ installed on your system
  • FastAPI framework installed (`pip install fastapi`)
  • Uvicorn server installed (`pip install uvicorn`) for running the application
  • PyJWT library for handling JWT tokens (`pip install PyJWT`)
  • Optional: `passlib` for password hashing (`pip install passlib`)

Ensure you have these packages installed before proceeding with the implementation.

Step 1: Set Up Your FastAPI Application

Start by creating a basic FastAPI application structure. Here’s a simple example:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Welcome to JWT Auth with FastAPI"}

This minimal setup provides the foundation on which to implement JWT authentication.

Step 2: User Data and Password Hashing

For demonstration, we'll use a dummy user database. In real applications, connect to a real database. Also, store hashed passwords instead of plain text for security.

from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Dummy user database
fake_users_db = {
    "john_doe": {
        "username": "john_doe",
        "full_name": "John Doe",
        "hashed_password": pwd_context.hash("secret"),
        "email": "john@example.com",
        "disabled": False,
    }
}

This setup uses `passlib` for hashing passwords securely. When creating users, always store hashed passwords.

Step 3: Utility Functions for Authentication

Create functions to verify passwords and generate JWT tokens.

import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def authenticate_user(username: str, password: str):
    user = fake_users_db.get(username)
    if not user:
        return False
    if not verify_password(password, user['hashed_password']):
        return False
    return user

def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

Adjust `SECRET_KEY` to a secure, random value in production.

Step 4: User Login Endpoint

Implement an endpoint where users submit their credentials to receive a JWT token.

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm

@app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user["username"]}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

This endpoint accepts username and password, authenticates the user, and returns a signed JWT.

Step 5: Dependency to Get Current User

To protect your endpoints, create a dependency that verifies the JWT token and retrieves user info.

from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    user = fake_users_db.get(username)
    if user is None:
        raise credentials_exception
    return user

This function decodes the token and retrieves the user data, raising an error if invalid or expired.

Step 6: Protecting Endpoints with JWT

Now, you can protect routes by requiring a valid JWT token.

@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
    return current_user

Any endpoint that depends on `get_current_user` will require a valid token, effectively securing your API routes.

Step 7: Testing Your JWT Authentication System

Run your FastAPI app with Uvicorn:

uvicorn main:app --reload

Use an API client like Postman or cURL to test the workflow:

  • POST to /token with form data: username and password
  • Receive a JWT token in response
  • Use the token in the Authorization header as Bearer <your_token> to access protected routes

Ensure your protected endpoints respond correctly when valid tokens are provided and deny access otherwise.

Best Practices for JWT Authentication in FastAPI

  • Always keep your SECRET_KEY secure and complex.
  • Implement token expiration and refresh mechanisms for better security.
  • Use HTTPS to encrypt tokens during transmission.
  • Handle token revocation via blacklists or short-lived tokens.
  • Implement role-based access control (RBAC) if needed, by adding roles to JWT claims.

Following these best practices will help you develop a robust, secure authentication system in your FastAPI applications.

Conclusion

Adding JWT authentication to your FastAPI application enhances security while maintaining the stateless advantage of RESTful APIs. By generating signed tokens upon successful login and verifying them for protected routes, you create a seamless and secure user experience. Remember to always prioritize security best practices, such as securing your secret keys, implementing token expiration, and transmitting tokens over HTTPS.

With this guide, you now have a clear understanding of how to integrate JWT authentication into your FastAPI projects. Start implementing today to safeguard your APIs and provide secure access to your users!


Disclaimer: Articles are written by Humans, AI or Both. Verify Important information.

Shrewdnia

Shrewdnia

Shrewdnia is a destination for curious minds seeking clarity, knowledge, and informed perspectives. Through insightful articles and practical guides our passionate team explores a wide range of topics designed to help readers understand the world around them, make smarter decisions, and stay informed in an ever-changing landscape.


💡 Every question sparks discovery, and every perspective enriches the conversation. Share your thoughts and insights in the comments 👇

Back to blog

Leave a comment

JOIN THE SHREWDNIA COMMUNITY FORUM

What do you think?

Have an opinion, experience, or question about this topic? Join the Shrewdnia Forum and share your thoughts with other readers.

Join the Forum →