Your Search Bar For Shrewd Tips

How To Install Jwt In Fastapi


How To Install JWT In FastAPI

JSON Web Tokens (JWT) are a popular method for implementing authentication and authorization in modern web applications. FastAPI, a high-performance Python web framework, seamlessly integrates with JWT to secure APIs efficiently. If you're looking to add JWT-based authentication to your FastAPI project, this comprehensive guide will walk you through the entire process—from installation to implementation. By the end of this tutorial, you'll have a robust JWT authentication system in place for your FastAPI application.

Prerequisites and Setup

Before diving into JWT integration, ensure you have a working FastAPI project and a Python environment set up. If you're starting from scratch, follow these steps:

  • Install Python 3.7+ on your system.
  • Create a new virtual environment for your project:
python -m venv env
source env/bin/activate   # On Windows use: env\Scripts\activate
  • Install FastAPI and Uvicorn, an ASGI server to run your app:
  • pip install fastapi uvicorn

    With these prerequisites met, you're ready to proceed with JWT integration.

    Step 1: Install Required Libraries

    FastAPI doesn't include JWT functionality out of the box. You'll need to install additional libraries that facilitate JWT encoding, decoding, and security handling. The most commonly used packages are:

    • PyJWT: A Python library for creating and verifying JWT tokens.
    • passlib: For hashing passwords securely.
    • python-multipart: To handle form data, if needed.

    Run the following command to install these libraries:

    pip install PyJWT passlib[bcrypt] python-multipart

    Here's a brief overview of these libraries:

    • PyJWT: Handles JWT token creation and validation.
    • passlib[bcrypt]: Provides secure password hashing, essential for user authentication.
    • python-multipart: Enables handling of multipart form data, useful for login forms.

    Step 2: Set Up User Authentication Models and Utilities

    To implement JWT authentication, you need user models and utility functions for password hashing and verification. Here's a simple example:

    from passlib.context import CryptContext
    
    # Create a password context for hashing
    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    
    # User data example (In real scenarios, use a database)
    fake_users_db = {
        "alice": {
            "username": "alice",
            "full_name": "Alice Wonderland",
            "hashed_password": pwd_context.hash("secret"),
            "disabled": False,
        }
    }
    
    def verify_password(plain_password, hashed_password):
        return pwd_context.verify(plain_password, hashed_password)
    
    def get_password_hash(password):
        return pwd_context.hash(password)
    
    def get_user(username: str):
        user = fake_users_db.get(username)
        return user
    

    This setup provides basic password handling. For production, integrate with a database like PostgreSQL or MySQL.

    Step 3: Create JWT Utility Functions

    Next, define functions to generate and verify JWT tokens. Use the jwt library from PyJWT:

    import jwt
    from datetime import datetime, timedelta
    
    # Secret key for encoding and decoding JWT
    SECRET_KEY = "your_secret_key"  # Replace with a secure key
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30
    
    def create_access_token(data: dict, expires_delta: timedelta = None):
        to_encode = data.copy()
        if expires_delta:
            expire = datetime.utcnow() + expires_delta
        else:
            expire = datetime.utcnow() + timedelta(minutes=15)
        to_encode.update({"exp": expire})
        encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
        return encoded_jwt
    
    def decode_access_token(token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            username: str = payload.get("sub")
            if username is None:
                return None
            return payload
        except jwt.PyJWTError:
            return None
    

    Replace your_secret_key with a secure, randomly generated key, especially for production environments.

    Step 4: Define FastAPI Dependencies for Authentication

    FastAPI uses dependency injection to handle authentication. Create a function to extract and verify JWT tokens from request headers:

    from fastapi import Depends, HTTPException, status
    from fastapi.security import OAuth2PasswordBearer
    
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
    
    async def get_current_user(token: str = Depends(oauth2_scheme)):
        payload = decode_access_token(token)
        if payload is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
        username: str = payload.get("sub")
        user = get_user(username)
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found",
                headers={"WWW-Authenticate": "Bearer"},
            )
        return user
    

    This function verifies the token and retrieves the user info, enabling protected routes.

    Step 5: Create Authentication Endpoints

    Implement a login route that authenticates users and returns a JWT token:

    from fastapi import FastAPI, Form
    
    app = FastAPI()
    
    @app.post("/token")
    async def login_for_access_token(
        username: str = Form(...),
        password: str = Form(...)
    ):
        user = get_user(username)
        if not user:
            raise HTTPException(status_code=400, detail="Incorrect username or password")
        if not verify_password(password, user["hashed_password"]):
            raise HTTPException(status_code=400, detail="Incorrect username or password")
        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 JWT token.

    Step 6: Protect Routes with JWT Authentication

    Use the get_current_user dependency to secure your API endpoints:

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

    This route will only be accessible with a valid JWT token provided in the Authorization header.

    Full Example: Combining All Components

    Here's a simplified but complete FastAPI app demonstrating JWT login and protected route:

    from fastapi import FastAPI, Depends, HTTPException, status, Form
    from fastapi.security import OAuth2PasswordBearer
    import jwt
    from datetime import datetime, timedelta
    from passlib.context import CryptContext
    
    app = FastAPI()
    
    # Password hashing setup
    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    
    # Fake user database
    fake_users_db = {
        "alice": {
            "username": "alice",
            "full_name": "Alice Wonderland",
            "hashed_password": pwd_context.hash("secret"),
            "disabled": False,
        }
    }
    
    # JWT configuration
    SECRET_KEY = "your_secret_key"
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30
    
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
    
    def verify_password(plain_password, hashed_password):
        return pwd_context.verify(plain_password, hashed_password)
    
    def get_user(username: str):
        user = fake_users_db.get(username)
        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})
        return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    
    def decode_access_token(token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            username: str = payload.get("sub")
            if username is None:
                return None
            return payload
        except jwt.PyJWTError:
            return None
    
    async def get_current_user(token: str = Depends(oauth2_scheme)):
        payload = decode_access_token(token)
        if payload is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
        username: str = payload.get("sub")
        user = get_user(username)
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found",
                headers={"WWW-Authenticate": "Bearer"},
            )
        return user
    
    @app.post("/token")
    async def login_for_access_token(
        username: str = Form(...),
        password: str = Form(...)
    ):
        user = get_user(username)
        if not user or not verify_password(password, user["hashed_password"]):
            raise HTTPException(status_code=400, detail="Incorrect username or password")
        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"}
    
    @app.get("/users/me")
    async def read_users_me(current_user: dict = Depends(get_current_user)):
        return current_user
    

    This example provides a full JWT authentication flow in FastAPI, from login to accessing protected routes.

    Best Practices and Tips

    • Secure Your Secret Key: Use environment variables or secret management tools to store your JWT secret key securely. Never hardcode in production code.
    • Token Expiration: Set appropriate expiration times for tokens to minimize security risks.
    • Refresh Tokens: Implement refresh tokens for longer sessions, allowing users to obtain new tokens without re-authentication.
    • HTTPS: Always serve your API over HTTPS, especially when transmitting tokens, to prevent man-in-the-middle attacks.
    • Validate Tokens: Always verify token signatures and expiration before granting access.

    Conclusion

    Integrating JWT authentication into your FastAPI application enhances security by providing stateless, scalable user authentication. The process involves installing necessary libraries, setting up user models and password hashing, creating JWT utility functions, and protecting routes with dependencies. While this guide covers the basics, remember to follow best security practices for production deployments, such as securing your secret keys, using HTTPS, and implementing refresh tokens. By mastering JWT in FastAPI, you can build secure, efficient, and scalable APIs suitable for modern web applications.


    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 →