Friday, November 7, 2025

thumbnail

Building Authentication for APIs in Python with JWT

 ๐Ÿง  1. What is JWT?


JWT (JSON Web Token) is a compact, URL-safe token used for authentication. It has three parts:


header.payload.signature



Header: Metadata about the token, usually the type (JWT) and algorithm (HS256).


Payload: Contains claims/data about the user (e.g., user_id, email, role).


Signature: Ensures the token hasn’t been tampered with using a secret key.


JWTs are stateless, meaning the server doesn’t need to store session info.


⚙️ 2. Setting Up Python Environment


You can use FastAPI, Flask, or Django. Here, we’ll use FastAPI for simplicity.


pip install fastapi uvicorn pyjwt passlib[bcrypt] python-multipart



pyjwt → JWT encoding/decoding


passlib[bcrypt] → Password hashing


python-multipart → Handling form data


๐Ÿงฉ 3. Creating the JWT Authentication Flow

Step 1: Import libraries

from fastapi import FastAPI, Depends, HTTPException, status

from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

from passlib.context import CryptContext

import jwt

from datetime import datetime, timedelta


Step 2: Setup secret key and algorithm

SECRET_KEY = "your_super_secret_key"

ALGORITHM = "HS256"

ACCESS_TOKEN_EXPIRE_MINUTES = 30


Step 3: Password hashing utility

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


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)


Step 4: OAuth2 scheme for token extraction

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


Step 5: Create token function

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


Step 6: Fake user database (for demo)

fake_users_db = {

    "alice": {

        "username": "alice",

        "full_name": "Alice Wonderland",

        "hashed_password": get_password_hash("secret123"),

        "disabled": False,

    }

}


Step 7: User authentication

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


Step 8: Create login endpoint to issue JWT

app = FastAPI()


@app.post("/token")

async def login(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",

        )

    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"}


Step 9: Dependency to get current user from token

def get_current_user(token: str = Depends(oauth2_scheme)):

    try:

        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])

        username: str = payload.get("sub")

        if username is None:

            raise HTTPException(status_code=401, detail="Invalid token")

        user = fake_users_db.get(username)

        if user is None:

            raise HTTPException(status_code=401, detail="User not found")

        return user

    except jwt.ExpiredSignatureError:

        raise HTTPException(status_code=401, detail="Token expired")

    except jwt.PyJWTError:

        raise HTTPException(status_code=401, detail="Invalid token")


Step 10: Protect API endpoints

@app.get("/users/me")

async def read_users_me(current_user: dict = Depends(get_current_user)):

    return current_user



Only accessible with a valid JWT in the Authorization: Bearer <token> header.


๐Ÿ” 4. Testing the Flow


Run FastAPI:


uvicorn main:app --reload



Obtain JWT token via /token endpoint (POST with username and password).


Access protected route /users/me with header:


Authorization: Bearer <your_jwt_token>



JWT expires after 30 minutes (configurable). Refresh mechanism can be added separately.


๐Ÿ’ก 5. Best Practices


Use HTTPS to prevent token interception.


Store secret keys securely (env variables or secret manager).


Short-lived access tokens + optional refresh tokens.


Validate token properly (expiration, signature, claims).


Handle blacklisting if a user logs out or tokens are revoked.


✅ Summary


JWT provides stateless authentication for APIs.


Secure password hashing and token signing are essential.


Protect endpoints by decoding and verifying JWT in requests.


Can be extended with refresh tokens, scopes/roles, and RBAC (Role-Based Access Control).

Learn Fullstack Python Training in Hyderabad

Read More

Using Django REST Framework for Building APIs

How to Build a RESTful API with Flask

Introduction to REST APIs with Python

Building APIs with Python

At Our Quality Thought Training Institute in Hyderabad

Get Directions


Subscribe by Email

Follow Updates Articles from This Blog via Email

No Comments

About

Search This Blog

Powered by Blogger.

Blog Archive