<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gopinath V</title>
    <description>The latest articles on DEV Community by Gopinath V (@gopinath_gopi_f141e1a8f90).</description>
    <link>https://dev.to/gopinath_gopi_f141e1a8f90</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3242117%2Fdb6ab85d-11c9-4493-81fc-5a2c66de1e43.png</url>
      <title>DEV Community: Gopinath V</title>
      <link>https://dev.to/gopinath_gopi_f141e1a8f90</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gopinath_gopi_f141e1a8f90"/>
    <language>en</language>
    <item>
      <title>🔐 FastAPI JWT Authentication with SQLite Database for Secure APIs</title>
      <dc:creator>Gopinath V</dc:creator>
      <pubDate>Sun, 20 Jul 2025 17:41:36 +0000</pubDate>
      <link>https://dev.to/gopinath_gopi_f141e1a8f90/fastapi-jwt-authentication-with-sqlite-database-for-secure-apis-kpf</link>
      <guid>https://dev.to/gopinath_gopi_f141e1a8f90/fastapi-jwt-authentication-with-sqlite-database-for-secure-apis-kpf</guid>
      <description>&lt;p&gt;Building robust and secure APIs is a cornerstone of modern web development. FastAPI, with its incredible speed and developer-friendly features, is a fantastic choice for this. When it comes to securing your API, JSON Web Tokens (JWT) offer a stateless and efficient authentication mechanism.&lt;/p&gt;

&lt;p&gt;In this blog post, we’ll walk through building a FastAPI application that integrates JWT-based authentication with a SQLite database for user management. We’ll cover everything from setting up your project, defining database models, implementing authentication logic, and securing your API endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Project Setup and Dependencies
&lt;/h3&gt;

&lt;p&gt;First, let’s get our project environment ready. We’ll use &lt;code&gt;pip&lt;/code&gt; and a pyproject.toml file to manage our dependencies.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;pyproject.toml&lt;/code&gt; specifies all the necessary libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pyproject.toml
[project]
name = "fastpi-jwt-auth"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = "&amp;gt;=3.11"
dependencies = [
    "fastapi&amp;gt;=0.116.1",
    "passlib[bcrypt]&amp;gt;=1.7.4",
    "pydantic&amp;gt;=2.11.7",
    "python-jose[cryptography]&amp;gt;=3.5.0",
    "python-multipart&amp;gt;=0.0.20",
    "sqlalchemy&amp;gt;=2.0.41",
    "uvicorn&amp;gt;=0.35.0",
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To install these, navigate to your project directory in the terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install -e .&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This command installs all dependencies listed in your &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Database Configuration (&lt;code&gt;database.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;We’ll use SQLite as our database for simplicity, which is perfect for development. SQLAlchemy is our chosen Object-Relational Mapper (ORM) to interact with the database.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;database.py&lt;/code&gt; file sets up the connection:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

# Define the URL for our SQLite database
# sqlite:///./todosapp.db means a file named todosapp.db in the current directory
DATABASE_URL = "sqlite:///./todosapp.db"
# Create the SQLAlchemy engine
# connect_args={"check_same_thread": False} is crucial for SQLite
# It tells SQLite that multiple threads might access the database connection,
# which is common in web servers like Uvicorn.
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
# Create a SessionLocal class for database sessions
# autocommit=False ensures transactions are managed manually
# autoflush=False prevents immediate flushing of changes
# bind=engine links sessions to our database engine
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Base class for our declarative models
# All SQLAlchemy models will inherit from this Base
Base = declarative_base()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Explanation:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DATABASE_URL&lt;/code&gt;: This specifies the path to your SQLite database file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_engine&lt;/code&gt;: This function creates a SQLAlchemy engine, which is responsible for communication with the database. The check_same_thread=False argument is essential for SQLite when used with multi-threaded environments like FastAPI's Uvicorn server, as SQLite typically expects to be accessed by only one thread.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sessionmaker&lt;/code&gt;: This creates a factory for new Session objects. Sessions are the primary way to interact with the database (add, query, update, delete).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;declarative_base&lt;/code&gt;: This function returns a base class for declarative model definitions. Your SQLAlchemy models will inherit from this Base.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3. Database Models (models.py)
&lt;/h4&gt;

&lt;p&gt;Next, we define our User model, which maps to a table in our SQLite database.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# models.py
from sqlalchemy import Column, String, Integer
from database import Base # Import Base from our database.py

class User(Base):
    # Define the table name in the database
    __tablename__ = 'users'
    # Define columns for the 'users' table
    id = Column(Integer, primary_key=True, index=True) # Primary key, auto-incrementing, indexed for fast lookups
    username = Column(String, unique=True) # Unique username
    password = Column(String) # Hashed password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Explanation:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;We import &lt;code&gt;Column&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, and &lt;code&gt;Integer&lt;/code&gt; from SQLAlchemy to define column types.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;User&lt;/code&gt; inherits from &lt;code&gt;Base&lt;/code&gt;, linking it to our SQLAlchemy declarative system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__tablename__&lt;/code&gt; = &lt;code&gt;'users'&lt;/code&gt; explicitly sets the table name in the database.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: An integer primary key that will be automatically managed by the database. index=True creates a database index on this column for faster queries.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;username&lt;/code&gt;: A string column for the username, set to unique=True to ensure no two users have the same username.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;password&lt;/code&gt;: A string column to store the hashed password. Never store plain pass
words!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. Authentication Logic (&lt;code&gt;auth.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This file is the heart of our authentication system, handling user creation, login, token generation, and token validation.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# auth.py
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, HTTPException, Depends
from typing import Annotated
from pydantic import BaseModel
from sqlalchemy.orm import Session
from starlette import status
from database import SessionLocal
from models import User
from passlib.context import CryptContext # For password hashing
from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer # For OAuth2 flow
from jose import JWTError, jwt # For JWT encoding/decoding

router = APIRouter(prefix="/auth", tags=["auth"])
# Secret key for signing JWTs - **CHANGE THIS IN PRODUCTION!**
SECRET_KEY = "0553abd6dc9e05eae3f5f0ae457d47ccbf9a10b90bfc9cba896c643cdf912c2cdf702314aa41a33a0cdcf294547eda3a"
ALGORITHM = "HS256" # Hashing algorithm for JWT
# Password hashing context (using bcrypt)
dcrypt_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# OAuth2PasswordBearer for handling token extraction from headers
oauth2_brearer = OAuth2PasswordBearer(tokenUrl="auth/token")
# Pydantic model for user registration request body
class CreateUserRequest(BaseModel):
    username: str
    password: str
# Pydantic model for token response
class Token(BaseModel):
    access_token: str
    token_type: str
# Dependency to get a database session
def get_db():
    db = SessionLocal() # Create a new session
    try:
        yield db # Yield the session to the FastAPI route
    finally:
        db.close() # Ensure the session is closed after the request
# Annotated dependency for easy type hinting in routes
db_dependancy = Annotated[Session, Depends(get_db)]
# --- API Endpoints ---
@router.post("/", status_code=status.HTTP_201_CREATED )
async def create_user(db: db_dependancy, user: CreateUserRequest):
    # Hash the password before storing it
    create_user_model = User(
        username=user.username,
        password=dcrypt_context.hash(user.password))
    db.add(create_user_model) # Add the new user to the session
    db.commit() # Commit the transaction to save to DB
    return {"message": "User created successfully"} # Return a success message
@router.post("/token", response_model=Token)
async def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: db_dependancy):
    # Authenticate user credentials
    user = authenticate_user(form_data.username, form_data.password, db)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"} # Standard header for auth challenges
        )
    # Create an access token for the authenticated user
    token = create_access_token(user.username, user.id, timedelta(minutes=30))
    return {"access_token": token, "token_type": "bearer"}
# --- Helper Functions ---
def authenticate_user(username:str, password: str, db):
    # Query database for user
    user = db.query(User).filter(User.username == username).first()
    if not user:
        return False # User not found
    # Verify provided password against hashed password
    if not dcrypt_context.verify(password, user.password):
        return False # Password mismatch
    return user # User authenticated
def create_access_token(username:str, user_id : int, expires_delta: timedelta | None = None):
    # Payload for the JWT
    to_encode = {"sub": username, "id": user_id} # 'sub' is standard for subject
    # Set token expiration time
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(minutes=15) # Default 15 min expiry
    to_encode.update({"exp": expire}) # Add expiration to payload
    # Encode the JWT using the secret key and algorithm
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def get_current_user(token: Annotated[str, Depends(oauth2_brearer)]):
    try:
        # Decode the token
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        user_id = payload.get("id")
        if username is None or user_id is None:
            # If payload is incomplete
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"}
            )
        return {"username": username, "id": user_id} # Return user info from token
    except JWTError:
        # If token is invalid or expired
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Could not validate credentials",
            headers={"WWW-Authenticate": "Bearer"}
        )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Explanation of &lt;code&gt;auth.py&lt;/code&gt;:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;APIRouter&lt;/code&gt;: Organizes our authentication-related endpoints under the &lt;code&gt;/auth&lt;/code&gt; prefix.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SECRET_KEY&lt;/code&gt;, &lt;code&gt;ALGORITHM&lt;/code&gt;: Essential for JWT signing and verification. Always use a strong, randomly generated key in production and keep it secret!&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CryptContext&lt;/code&gt; (&lt;code&gt;passlib&lt;/code&gt;): Used to securely hash and verify user passwords (using bcrypt in this case). This is critical for security.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OAuth2PasswordBearer&lt;/code&gt; (&lt;code&gt;fastapi.security&lt;/code&gt;): This class handles extracting the token from the Authorization: Bearer  header of incoming requests. tokenUrl points to our login endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CreateUserRequest&lt;/code&gt;, Token (&lt;code&gt;Pydantic Models&lt;/code&gt;): Define the expected structure for incoming request bodies (for user creation) and outgoing response bodies (for the token).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_db()&lt;/code&gt; Dependency: This is a core FastAPI pattern. It provides a database session (&lt;code&gt;SessionLocal&lt;/code&gt;) for each request and ensures the session is properly closed afterward, preventing resource leaks. The &lt;code&gt;yield&lt;/code&gt; keyword makes it a dependency.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db_dependancy&lt;/code&gt;: An Annotated type hint that simplifies injecting the database session into our route functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;@router.post("/") (Create User)&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes &lt;code&gt;CreateUserRequest&lt;/code&gt; as input for &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Hashes the password using &lt;code&gt;dcrypt_context.hash()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creates a new User object, adds it to the database session, and commits the transaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;@router.post("/token") (Login)&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;OAuth2PasswordRequestForm&lt;/code&gt; to expect &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; as form data (standard for OAuth2 token endpoints).&lt;/li&gt;
&lt;li&gt;Calls authenticate_user to verify credentials. If invalid, raises HTTPException(401 UNAUTHORIZED).&lt;/li&gt;
&lt;li&gt;If authenticated, calls &lt;code&gt;create_access_token&lt;/code&gt; to generate a JWT.&lt;/li&gt;
&lt;li&gt;Returns the JWT and token type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;authenticate_user()&lt;/code&gt;: Queries the database for the user and verifies the password using dcrypt_context.verify().&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
  
  
  &lt;code&gt;create_access_token()&lt;/code&gt;:
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Constructs the JWT payload including sub (subject, here &lt;code&gt;username&lt;/code&gt;) and &lt;code&gt;id&lt;/code&gt; (user ID).&lt;/li&gt;
&lt;li&gt;Sets an exp (expiration) timestamp for the token. JWTs are usually short-lived.&lt;/li&gt;
&lt;li&gt;Encodes the payload using &lt;code&gt;jwt.encode()&lt;/code&gt; with the SECRET_KEY and ALGORITHM.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
  
  
  &lt;code&gt;get_current_user() Dependency:&lt;/code&gt;
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;This function is itself a dependency. It uses &lt;code&gt;oauth2_brearer&lt;/code&gt; to get the token from the request.&lt;/li&gt;
&lt;li&gt;It then decodes and validates the JWT using &lt;code&gt;jwt.decode()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the token is invalid, expired, or missing essential data, it raises an &lt;code&gt;HTTPException(401 UNAUTHORIZED)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If successful, it returns a dictionary containing the authenticated user’s username and id.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  5. Main Application (&lt;code&gt;main.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This is our main FastAPI application file, where we tie everything together.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# main.py
from fastapi import FastAPI, HTTPException, status, Depends
import auth # Import our authentication module
import models # Import our models module
from database import engine, SessionLocal # Import engine and SessionLocal from database.py
from sqlalchemy.orm import Session
from typing import Annotated
from auth import get_current_user # Import the get_current_user dependency

app = FastAPI()
# Include the authentication router, making its endpoints available
app.include_router(auth.router)
# Create database tables defined in models.py when the application starts
# This will create the 'users' table if it doesn't already exist
models.Base.metadata.create_all(bind=engine)
# This get_db is duplicated in auth.py, but it's good practice to have it
# readily available in main.py if other parts of the app need a DB session.
# For this specific setup, the one in auth.py is sufficient for auth routes.
# However, for new routes in main.py, this would be used.
def get_db():
    try:
        db = SessionLocal()
        yield db
    finally:
        db.close()
# Annotated dependencies for easy use
db_dependancy = Annotated[Session, Depends(get_db)] # Database session dependency
user_dependancy = Annotated[dict, Depends(get_current_user)] # Current authenticated user dependency
# An example protected endpoint
@app.get('/', status_code=status.HTTP_200_OK)
async def user(user: user_dependancy, db: db_dependancy):
    # The get_current_user dependency already handles authentication
    # If get_current_user raises an HTTPException, this code won't be reached.
    # So, a simple check if user is None here is redundant if get_current_user is robust.
    # We can directly use the 'user' dictionary.
    return {"message": f"Hello, {user['username']} with ID: {user['id']}!"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;code&gt;@app.get('/') (Protected Endpoint)&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is an example of a route that requires authentication.&lt;/li&gt;
&lt;li&gt;By adding user: user_dependancy, FastAPI will automatically execute get_current_user. If get_current_user successfully returns user data (meaning the token is valid), that data will be passed to the user parameter. If get_current_user raises an HTTPException, FastAPI will return that error response directly, and the code inside async def user will not execute.&lt;/li&gt;
&lt;li&gt;It now returns a personalized greeting using the extracted username and id from the token payload.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":: This standard Python construct allows you to run your application directly using uvicorn.&lt;br&gt;
&lt;strong&gt;Install dependencies:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pip install -e .&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Run the application:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;python main.py&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should see output indicating Uvicorn is running, typically on &lt;code&gt;http://0.0.0.0:8000&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access FastAPI Docs: Open your browser and go to &lt;code&gt;http://127.0.0.1:8000/docs&lt;/code&gt; (or &lt;code&gt;http://localhost:8000/docs&lt;/code&gt;). You'll see the interactive API documentation (Swagger UI).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Testing the Endpoints:
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Create a User (Sign Up)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go to /docs.&lt;/li&gt;
&lt;li&gt;Find the POST /auth/ endpoint.&lt;/li&gt;
&lt;li&gt;Click “Try it out”.&lt;/li&gt;
&lt;li&gt;In the “Request body” field, enter a username and password:&lt;/li&gt;
&lt;li&gt;{ "username": "testuser", "password": "testpassword" }&lt;/li&gt;
&lt;li&gt;Click “Execute”. You should get a 201 Created response. This will create the todosapp.db file in your project directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2. Log In and Get a Token
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Find the POST /auth/token endpoint.&lt;/li&gt;
&lt;li&gt;Click “Try it out”.&lt;/li&gt;
&lt;li&gt;For username and password fields, enter the credentials you just created (testuser, testpassword).&lt;/li&gt;
&lt;li&gt;Click “Execute”.&lt;/li&gt;
&lt;li&gt;You should receive a 200 OK response with an access_token and token_type: "bearer". Copy the access_token value.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  3. Access a Protected Endpoint
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;At the top right of the Swagger UI, click the “Authorize” button (or the lock icon next to the endpoints).&lt;/li&gt;
&lt;li&gt;In the dialog box, under “BearerAuth”, paste your copied access_token into the Value field (without the "Bearer " prefix, just the token itself).&lt;/li&gt;
&lt;li&gt;Click “Authorize”, then “Close”.&lt;/li&gt;
&lt;li&gt;Now, try the GET / endpoint.&lt;/li&gt;
&lt;li&gt;Click “Try it out” and then “Execute”.&lt;/li&gt;
&lt;li&gt;You should receive a 200 OK response with a message like: {"message": "Hello, {'username': 'testuser', 'id': 1}!"}.&lt;/li&gt;
&lt;li&gt;If you try to access the GET / endpoint without authorization (by clicking "Unauthorize" first, or not providing a token), you will get a 401 Unauthorized error.
If want to try the Basic Authentication — have a look at this &lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l" class="crayons-story__hidden-navigation-link"&gt;Implementing Basic Authentication in FastAPI&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/gopinath_gopi_f141e1a8f90" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3242117%2Fdb6ab85d-11c9-4493-81fc-5a2c66de1e43.png" alt="gopinath_gopi_f141e1a8f90 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/gopinath_gopi_f141e1a8f90" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Gopinath V
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Gopinath V
                
              
              &lt;div id="story-author-preview-content-2691335" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/gopinath_gopi_f141e1a8f90" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3242117%2Fdb6ab85d-11c9-4493-81fc-5a2c66de1e43.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Gopinath V&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l" id="article-link-2691335"&gt;
          Implementing Basic Authentication in FastAPI
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/api"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;api&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/fastapi"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;fastapi&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;/div&gt;

&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>fastapi</category>
      <category>jwt</category>
    </item>
    <item>
      <title>Implementing Basic Authentication in FastAPI</title>
      <dc:creator>Gopinath V</dc:creator>
      <pubDate>Tue, 15 Jul 2025 18:46:15 +0000</pubDate>
      <link>https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l</link>
      <guid>https://dev.to/gopinath_gopi_f141e1a8f90/implementing-basic-authentication-in-fastapi-410l</guid>
      <description>&lt;p&gt;Basic Authentication in your FastAPI applications! Whether you’re building a simple internal API or just getting started with API security, understanding Basic Auth is a fundamental step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is HTTP Basic Authentication?&lt;/strong&gt;&lt;br&gt;
HTTP Basic Authentication is the simplest form of authentication built directly into the HTTP protocol. It works by sending the user’s username and password (separated by a colon, then Base64 encoded) in the Authorization header of every HTTP request.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example Authorization Header:
&lt;/h3&gt;

&lt;p&gt;When a client tries to access a protected resource, the server responds with a 401 Unauthorized status and a WWW-Authenticate: Basic realm="" header. The client (usually a web browser or an API client like Postman/curl) then prompts the user for a username and password. These credentials are then combined (username:password), base64 encoded, and sent in the Authorization header of the subsequent request, like this:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== (where QWxhZGRpbjpvcGVuIHNlc2FtZQ== is the Base64 encoding of Aladdin:open sesame)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will go by each step to start will prerequistes.&lt;/p&gt;

&lt;p&gt;Prerequisites&lt;br&gt;
Before we start, make sure you have Python installed (3.7+) and the necessary libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install fastapi uvicorn "python-multipart[optional]" # python-multipart for form data, optional but good practice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Project Setup
&lt;/h2&gt;

&lt;p&gt;Let’s create a simple project structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
fastapi_basic_auth/
├── main.py
└── .env (optional, for storing sensitive data)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Define Your Users (for demonstration)
&lt;/h2&gt;

&lt;p&gt;For a real application, you’d fetch user credentials from a database. For this example, we’ll hardcode a few users. Never hardcode passwords in a real application! Always store hashed passwords in a database.&lt;/p&gt;

&lt;p&gt;Open main.py and start by importing FastAPI and some authentication utilities from fastapi.security.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import uvicorn # For running the app directly if desired

app = FastAPI()
security = HTTPBasic() # Initialize HTTPBasic authentication
# Hardcoded users for demonstration. In a real app, fetch from DB!
# Passwords should ALWAYS be hashed (e.g., using bcrypt) in a real app.
USERS_DB = {
    "admin": "supersecret",
    "john.doe": "password123",
    "jane.smith": "securepass"
}
# Dummy function to simulate password verification (replace with bcrypt.checkpw in real app)
def verify_password(plain_password: str, stored_password: str) -&amp;gt; bool:
    # In a real app, this would be e.g., bcrypt.checkpw(plain_password.encode(), stored_password_hash)
    return plain_password == stored_password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Security Note: The USERS_DB and verify_password function here are highly insecure for production. They are purely for demonstrating the authentication flow. In a real application, you'd use libraries like passlib (with bcrypt or scrypt) to hash and verify passwords securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create the Authentication Dependency
&lt;/h2&gt;

&lt;p&gt;FastAPI’s dependency injection system is perfect for handling authentication. We’ll create a function that verifies the provided credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  main.py (continued)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# ... (previous imports and USERS_DB, verify_password function) ...
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
    """
    Dependency to get and verify the current user's username based on Basic Auth.
    """
    username = credentials.username
    password = credentials.password
    if username not in USERS_DB:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Basic"},
        )
    if not verify_password(password, USERS_DB[username]):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Basic"},
        )
    return username # Return the username if authentication is successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explanation of get_current_username:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;credentials: HTTPBasicCredentials = Depends(security)&lt;/strong&gt;:&lt;br&gt;
&lt;code&gt;HTTPBasicCredentials&lt;/code&gt; is a Pydantic model (provided by FastAPI) that will automatically parse the Authorization header for Basic Auth, extracting username and password.&lt;br&gt;
&lt;code&gt;Depends(security)&lt;/code&gt;: This tells FastAPI to:&lt;br&gt;
Check for the Authorization: Basic header.&lt;br&gt;
If not present or malformed, return a 401 Unauthorized with the WWW-&lt;code&gt;Authenticate: Basic&lt;/code&gt; header, prompting the client for credentials.&lt;br&gt;
If present, decode the credentials and inject them into the credentials parameter as an HTTPBasicCredentials object.&lt;br&gt;
Verification Logic:&lt;br&gt;
We first check if the username exists in our USERS_DB.&lt;br&gt;
Then, we use verify_password to compare the provided password with the stored one.&lt;br&gt;
&lt;strong&gt;HTTPException&lt;/strong&gt;: If authentication fails at any point, we raise an HTTPException with:&lt;br&gt;
&lt;code&gt;status.HTTP_401_UNAUTHORIZED&lt;/code&gt;: The standard HTTP status code for unauthorized access.&lt;br&gt;
detail: A custom message for the client.&lt;br&gt;
&lt;code&gt;headers={"WWW-Authenticate": "Basic"}&lt;/code&gt;: This crucial header tells the client (especially browsers) how to authenticate, prompting the browser's native login dialog.&lt;br&gt;
&lt;code&gt;Return username&lt;/code&gt;: If both checks pass, the function returns the username. This username can then be used by your endpoint function.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Protect Your API Endpoints
&lt;/h2&gt;

&lt;p&gt;Now, you can use this get_current_username dependency to protect your routes.&lt;/p&gt;
&lt;h3&gt;
  
  
  main.py (continued)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# ... (previous code) ...
@app.get("/unprotected/")
async def unprotected_route():
    """An endpoint that doesn't require authentication."""
    return {"message": "This endpoint is open to everyone!"}
@app.get("/protected/")
async def protected_route(username: str = Depends(get_current_username)):
    """
    An endpoint that requires Basic Authentication.
    The 'username' parameter will receive the authenticated username.
    """
    return {"message": f"Welcome, {username}! You accessed a protected endpoint."}
@app.get("/protected-admin/")
async def protected_admin_route(username: str = Depends(get_current_username)):
    """
    An endpoint that requires Basic Authentication and checks for 'admin' role.
    """
    if username != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="You do not have permission to access this resource.",
        )
    return {"message": f"Hello, Admin {username}! This is a top-secret route."}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Explanation of Endpoint Usage:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/unprotected/&lt;/strong&gt;: No Depends on get_current_username, so it's publicly accessible.&lt;br&gt;
&lt;strong&gt;/protected/&lt;/strong&gt;: By adding &lt;code&gt;username: str = Depends(get_current_username)&lt;/code&gt;, this endpoint now requires Basic Authentication. If authentication succeeds, the username variable inside the function will hold the authenticated username.&lt;br&gt;
&lt;strong&gt;/protected-admin/&lt;/strong&gt;: This demonstrates adding authorization logic after authentication. Once the user is authenticated, we check if their username is "admin" to grant access to this specific resource. If not, a 403 Forbidden is returned.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 5: Run Your FastAPI Application
&lt;/h2&gt;

&lt;p&gt;To run your application, use Uvicorn from your terminal. Navigate to the directory containing main.py.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvicorn main:app --reload --port 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main&lt;/code&gt;: Refers to your main.py file.&lt;br&gt;
&lt;code&gt;app&lt;/code&gt;: Refers to the FastAPI() instance named app inside main.py.&lt;br&gt;
&lt;code&gt;--reload&lt;/code&gt;: Useful for development; Uvicorn will restart whenever you save changes.&lt;br&gt;
&lt;code&gt;--port 8000&lt;/code&gt;: Runs the server on port 8000.&lt;br&gt;
You should see output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO:     Will watch for changes in these directories: ['/path/to/your/fastapi_basic_auth']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [xxxxx]
INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Test Your Endpoints
&lt;/h2&gt;

&lt;p&gt;Open your web browser or an API client like Postman/Insomnia.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access &lt;code&gt;http://127.0.0.1:8000/unprotected/:&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;You should see: {"message":"This endpoint is open to everyone!"}. No authentication requi
red.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access &lt;code&gt;http://127.0.0.1:8000/protected/:&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In a Browser: Your browser will pop up a native Basic Auth login dialog.&lt;br&gt;
Try:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Username: wrong_user, Password: any_password -&amp;gt; You'll get 401 Unauthorized repeatedly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Username: john.doe, Password: password123 -&amp;gt; You should see: {"message":&lt;br&gt;
"Welcome, john.doe! You accessed a protected endpoint."}.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access &lt;a href="http://127.0.0.1:8000/protected-admin/:" rel="noopener noreferrer"&gt;http://127.0.0.1:8000/protected-admin/:&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try with john.doe:password123: You'll get {"detail":"You do not have permission to access this resource."} (Status 403 Forbidden).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try with admin:supersecret: You should see: {"message":"Hello, Admin admin! T&lt;br&gt;
his is a top-secret route."}.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Important Security Considerations for Production&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As mentioned, Basic Auth is simple but has limitations. Always use HTTPS in production! Without it, the base64-encoded credentials are easily intercepted. For more robust security, consider these alternatives:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OAuth 2.0 / OpenID Connect: The industry standard for user authentication and authorization, providing token-based security, refresh tokens, and more complex flows suitable for public-facing applications. Libraries like Authlib can help.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JWT (JSON Web Tokens): Often used in conjunction with Bearer Token authentication. JWTs can carry signed (and optionally encrypted) claims, allowing stateless authentication. FastAPI has excellent support for JWTs.&lt;br&gt;
&lt;strong&gt;API Key Management&lt;/strong&gt;: If using API keys, ensure they are:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Revocable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have expiration dates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Associated with specific user accounts or roles for fine-grained control.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>api</category>
      <category>fastapi</category>
    </item>
  </channel>
</rss>
