> ## Documentation Index
> Fetch the complete documentation index at: https://fastapi.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# JWT Authentication

> Understand the fundamentals of JSON Web Tokens (JWT), their structure, how they work, and why they are widely used for securing REST APIs.

# Introduction to JWT Authentication

JSON Web Token (JWT) is a **stateless authentication mechanism** used to securely exchange user information between a client and a server. After a successful login, the server generates a signed token and sends it to the client. The client includes this token in the `Authorization` header of subsequent requests, allowing the server to authenticate the user without storing any session information.

Unlike Session-Based Authentication, the server does **not** maintain authentication state. Instead, all the information required to authenticate the user is contained within the JWT.

For a deeper understanding of JWT, including how tokens are encoded and decoded, visit the official JWT website:

:contentReference\[oaicite:0]{index=0}

## What is a JWT?

A JWT is a compact, URL-safe string consisting of **three parts** separated by dots (`.`).

```text theme={null}
xxxxx.yyyyy.zzzzz
```

Each part has a specific purpose.

```text theme={null}
Header.Payload.Signature
```

## Structure of a JWT

```text theme={null}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjMiLCJ1c2VybmFtZSI6ImpvaG4iLCJyb2xlIjoiYWRtaW4ifQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

### 1. Header

The header contains metadata about the token.

Typical information includes:

* Token type (`JWT`)
* Signing algorithm (for example, `HS256`)

Example:

```json theme={null}
{
    "alg": "HS256",
    "typ": "JWT"
}
```

### 2. Payload

The payload contains information (called **claims**) about the authenticated user.

Typical claims include:

* User ID
* Username
* Email
* Role
* Permissions
* Issued time (`iat`)
* Expiration time (`exp`)

Example:

```json theme={null}
{
    "sub": "1",
    "username": "john",
    "role": "admin",
    "exp": 1750000000
}
```

> **Note:** The payload is **Base64URL encoded**, **not encrypted**. Anyone possessing the token can decode and read its contents. Therefore, never store sensitive information such as passwords or secret keys inside a JWT.

### 3. Signature

The signature is generated using:

* Header
* Payload
* Secret key
* Signing algorithm

The signature allows the server to verify that:

* The token has not been modified.
* The token was generated by a trusted server.

Without the server's secret key, a client cannot generate a valid signature.

## Complete JWT Authentication & Authorization Flow

```text theme={null}
Client
  │
  ▼
Login
  │
  ▼
Verify Credentials
  │
  ├───────────────┐
  │               │
Invalid         Valid
  │               │
  ▼               ▼
401      Generate JWT
                  │
                  ▼
             Return JWT
                  │
        ── Future Requests ──
                  │
                  ▼
 Authorization: Bearer <JWT>
                  │
                  ▼
          Extract JWT
                  │
         ├──────────────┐
         │              │
     Missing        Present
         │              │
         ▼              ▼
       401      Validate Signature
                         │
                ├──────────────┐
                │              │
            Invalid         Valid
                │              │
                ▼              ▼
              401      Validate Expiry
                               │
                      ├──────────────┐
                      │              │
                   Expired        Valid
                      │              │
                      ▼              ▼
                    401      Extract Claims
                                     │
                                     ▼
                              Retrieve User
                                     │
                           ├────────────────┐
                           │                │
                     Not Found         User Found
                           │                │
                           ▼                ▼
                         401          Check Role
                                          │
                                  ├────────────┐
                                  │            │
                             Forbidden    Authorized
                                  │            │
                                  ▼            ▼
                                 403     Execute API
```

## Authorization Header

The client sends the JWT using the `Authorization` header.

```http theme={null}
Authorization: Bearer <JWT>
```

Example:

```http theme={null}
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

## Why is JWT Stateless?

Unlike Session-Based Authentication, the server does not store authentication sessions.

```text theme={null}
Session Authentication

Server
├── Session 1
├── Session 2
└── Session 3
```

```text theme={null}
JWT Authentication

Server
└── Secret Key

Client
└── JWT
```

The server only needs its secret key to verify incoming tokens.

## Advantages of JWT Authentication

* Users authenticate only once by logging in.
* Username and password are **not sent with every request**.
* No server-side session storage is required.
* Stateless authentication improves scalability.
* Works well with REST APIs, mobile applications, and microservices.
* Tokens are digitally signed, allowing the server to detect tampering.
* JWT can carry useful user information (claims), such as:
  * User ID
  * Username
  * Email
  * Roles
  * Permissions
* Roles and permissions can be used directly for authorization checks.
* Works seamlessly with Single Page Applications (SPA) and third-party clients.
* Reduces database lookups when appropriate because user claims travel with the token.

## Limitations

* Tokens cannot be easily revoked before they expire.
* The payload is encoded, not encrypted.
* Sensitive information should never be stored in the payload.
* A JWT is larger than a session ID and is sent with every request.
* Short-lived access tokens are recommended for better security.
* If user roles or permissions change, applications often retrieve the latest user information from the database instead of relying solely on the claims inside the token.

## Typical Use Cases

* REST APIs
* Mobile applications
* Single Page Applications (SPA)
* Microservices
* Cloud-native applications

## Comparison

| Feature                            | Session Authentication | JWT Authentication |
| ---------------------------------- | ---------------------- | ------------------ |
| Server Stores Authentication State | Yes                    | No                 |
| Uses Cookies                       | Yes                    | Optional           |
| Uses Authorization Header          | No                     | Yes                |
| Stateless                          | No                     | Yes                |
| Suitable for REST APIs             | Moderate               | Excellent          |
| Scalability                        | Moderate               | Excellent          |
| Supports Mobile Apps               | Limited                | Excellent          |
| Easy Token Revocation              | Yes                    | Limited            |

## What We Will Implement

In this section, we will implement:

* User registration.
* Password hashing.
* User login.
* JWT generation.
* JWT validation.
* Authentication dependency.
* Public and protected endpoints.
* Role-based authorization in the next section.

## Task 1 - Create the Project

### Goal

Create a new FastAPI project for implementing **JWT Authentication** using **SQLite**.

### Create the Project

```bash theme={null}
mkdir jwt_auth_app
cd jwt_auth_app

uv init
uv add fastapi uvicorn sqlmodel passlib bcrypt python-multipart pyjwt
```

### Installed Packages

| Package            | Purpose                                                                               |
| ------------------ | ------------------------------------------------------------------------------------- |
| `fastapi`          | Build REST APIs.                                                                      |
| `uvicorn`          | ASGI server for running the FastAPI application.                                      |
| `sqlmodel`         | Define models and interact with the SQLite database.                                  |
| `passlib`          | Hash and verify user passwords.                                                       |
| `bcrypt`           | Secure hashing algorithm used by Passlib.                                             |
| `python-multipart` | Parse form data and file uploads (required by FastAPI for some authentication flows). |
| `pyjwt`            | Generate, sign, decode, and validate JSON Web Tokens (JWT).                           |

### Create the Project Structure

```text theme={null}
jwt_auth_app/
│
├── app.py
├── database.py
├── models.py
├── auth.py
├── pyproject.toml
├── uv.lock
└── .venv/
```

Create the required files.

**Windows**

```bash theme={null}
type nul > app.py
type nul > database.py
type nul > models.py
type nul > auth.py
```

**macOS / Linux**

```bash theme={null}
touch app.py database.py models.py auth.py
```

### Update `database.py`

```python theme={null}
from sqlmodel import Session, create_engine

DATABASE_URL = "sqlite:///jwt_auth.db"

engine = create_engine(DATABASE_URL, echo=True)


def get_session():
    with Session(engine) as session:
        yield session
```

### Update `app.py`

```python theme={null}
from fastapi import FastAPI
from sqlmodel import SQLModel

from database import engine
from models import User

SQLModel.metadata.create_all(engine)

app = FastAPI()


@app.get("/")
def root():
    return {
        "message": "JWT Authentication API"
    }
```

### Run the Application

```bash theme={null}
uv run uvicorn app:app --reload
```

### Verify

Open the following URLs:

* [http://127.0.0.1:8000](http://127.0.0.1:8000)
* [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)

### Expected Outcome

At the end of this task, you should have:

* A new FastAPI project.
* All required dependencies installed.
* A configured SQLite database.
* A running FastAPI application.
* The project ready for implementing JWT authentication.

## Task 2 - Create the User Model

### Goal

Create the `User` model and request models required for implementing JWT authentication.

### Update `models.py`

```python theme={null}
from sqlmodel import Field, SQLModel


class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    username: str = Field(index=True, unique=True)
    password: str


class RegisterRequest(SQLModel):
    username: str
    password: str


class LoginRequest(SQLModel):
    username: str
    password: str
```

### Run the Application

```bash theme={null}
uv run uvicorn app:app --reload
```

### Verify

After restarting the application, a new SQLite database named `jwt_auth.db` should be created with a `user` table.

| Column   | Type    |
| -------- | ------- |
| id       | INTEGER |
| username | TEXT    |
| password | TEXT    |

### Note

Unlike Session-Based Authentication, JWT Authentication does **not** require a `Session` table. The server does not store authentication state. Instead, all authentication information is carried inside the JWT, making the application **stateless**.

### Expected Outcome

At the end of this task, you should have:

* A `User` model.
* Request models for registration and login.
* A `user` table created automatically in the SQLite database.

## Task 3 - Implement Password Hashing

### Goal

Implement password hashing and password verification using `bcrypt`.

### Update `auth.py`

```python theme={null}
from passlib.context import CryptContext

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


def hash_password(password: str) -> str:
    return pwd_context.hash(password)


def verify_password(password: str, hashed_password: str) -> bool:
    return pwd_context.verify(password, hashed_password)


if __name__ == "__main__":
    password = "secret123"

    hashed_password = hash_password(password)

    print(f"Original Password : {password}")
    print(f"Hashed Password   : {hashed_password}")
    print(f"Password Verified : {verify_password(password, hashed_password)}")
```

### Run the File

```bash theme={null}
uv run auth.py
```

### Expected Output

```text theme={null}
Original Password : secret123
Hashed Password   : $2b$12$...
Password Verified : True
```

### Why Hash Passwords?

Passwords should never be stored as plain text. Instead, only their hashed values are stored in the database. During authentication, the entered password is verified against the stored hash.

### Expected Outcome

At the end of this task, you should have:

* A reusable password hashing function.
* A reusable password verification function.
* A secure mechanism for storing user passwords.

## Task 4 - Implement User Registration

### Goal

Create an API to register new users by storing their username and hashed password in the database.

### Update `app.py`

Import the required modules.

```python theme={null}
from fastapi import Depends, HTTPException
from sqlmodel import Session, select

from auth import hash_password
from database import get_session
from models import RegisterRequest, User
```

Implement the registration endpoint.

```python theme={null}
@app.post("/register")
def register(
    request: RegisterRequest,
    session: Session = Depends(get_session)
):
    existing_user = session.exec(
        select(User).where(User.username == request.username)
    ).first()

    if existing_user:
        raise HTTPException(
            status_code=400,
            detail="Username already exists."
        )

    user = User(
        username=request.username,
        password=hash_password(request.password)
    )

    session.add(user)
    session.commit()
    session.refresh(user)

    return {
        "message": "User registered successfully."
    }
```

### Run the Application

```bash theme={null}
uv run uvicorn app:app --reload
```

### Test the API

Open the Swagger UI.

```text theme={null}
http://127.0.0.1:8000/docs
```

Call:

```http theme={null}
POST /register
```

Request Body

```json theme={null}
{
    "username": "john",
    "password": "secret123"
}
```

### Verify

Open the `user` table in the SQLite database.

The password should be stored as a hashed value similar to:

```text theme={null}
$2b$12$...
```

instead of

```text theme={null}
secret123
```

### Expected Outcome

At the end of this task, you should have:

* A working user registration API.
* Duplicate username validation.
* Passwords stored securely using hashing.

## Task 5 - Implement Login and Generate JWT

### Goal

Authenticate users using their username and password. Upon successful authentication, generate a JWT and return it to the client.

### Update `auth.py`

Import the required modules.

```python theme={null}
from datetime import datetime, timedelta, timezone

import jwt
```

Add the following constants.

```python theme={null}
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
```

Implement the JWT generation function.

```python theme={null}
def create_access_token(data: dict) -> str:
    payload = data.copy()

    payload["exp"] = (
        datetime.now(timezone.utc)
        + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    )

    return jwt.encode(
        payload,
        SECRET_KEY,
        algorithm=ALGORITHM
    )
```

### Update `app.py`

Import the required modules.

```python theme={null}
from fastapi import Depends, HTTPException, status
from sqlmodel import Session, select

from auth import create_access_token, verify_password
from database import get_session
from models import LoginRequest, User
```

Implement the login endpoint.

```python theme={null}
@app.post("/login")
def login(
    request: LoginRequest,
    session: Session = Depends(get_session),
):
    user = session.exec(
        select(User).where(User.username == request.username)
    ).first()

    if not user or not verify_password(request.password, user.password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password."
        )

    access_token = create_access_token(
        {
            "sub": str(user.id),
            "username": user.username,
        }
    )

    return {
        "access_token": access_token,
        "token_type": "bearer"
    }
```

### How It Works

1. Receive the username and password.
2. Retrieve the user from the database.
3. Verify the password.
4. Create the JWT payload.
5. Add an expiration time.
6. Sign the JWT using the secret key.
7. Return the JWT to the client.

### Run the Application

```bash theme={null}
uv run uvicorn app:app --reload
```

### Test the API

Open the Swagger UI.

```text theme={null}
http://127.0.0.1:8000/docs
```

Call:

```http theme={null}
POST /login
```

Request Body

```json theme={null}
{
    "username": "john",
    "password": "secret123"
}
```

### Expected Response

```json theme={null}
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer"
}
```

Copy the generated JWT.

You can paste it into the debugger available at:

:contentReference\[oaicite:0]{index=0}

Observe the decoded:

* Header
* Payload
* Signature

### Expected Outcome

At the end of this task, you should have:

* A working login API.
* Username and password verification.
* JWT generation.
* Signed access tokens with an expiration time.

## Task 6 - Validate JWT and Authenticate Users

### Goal

Validate the JWT received in the `Authorization` header and return the authenticated user.

### Update `auth.py`

Import the required modules.

```python theme={null}
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlmodel import Session

from database import get_session
from models import User

security = HTTPBearer()
```

Implement the authentication dependency.

```python theme={null}
def authenticate_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    session: Session = Depends(get_session),
) -> User:

    token = credentials.credentials

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

        user_id = int(payload["sub"])

    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or expired token."
        )

    user = session.get(User, user_id)

    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found."
        )

    return user
```

### Nested Dependencies

The `authenticate_user()` function is itself a dependency and depends on two other dependencies.

* `HTTPBearer()` extracts the Bearer token from the `Authorization` header.
* `get_session()` provides a database session.

```text theme={null}
authenticate_user()
        │
        ├──────────────┐
        ▼              ▼
Depends(security)  Depends(get_session)
        │              │
        ▼              ▼
 Bearer Token    Database Session
```

### How It Works

1. Read the Bearer token from the `Authorization` header.
2. Verify the JWT signature.
3. Verify the token has not expired.
4. Extract the user ID from the token.
5. Retrieve the user from the database.
6. Return the authenticated user.
7. Return **401 Unauthorized** if the token is invalid, expired, or the user does not exist.

### Authorization Header

The client must send the JWT as a Bearer token.

```http theme={null}
Authorization: Bearer <JWT>
```

### Expected Outcome

At the end of this task, you should have:

* A reusable JWT authentication dependency.
* JWT signature validation.
* Token expiration validation.
* Retrieval of the authenticated user.
* Proper `401 Unauthorized` responses for invalid or expired tokens.

## Task 7 - Create Public and Protected Endpoints

### Goal

Create public and protected endpoints using JWT authentication.

### Update `app.py`

Import the authentication dependency.

```python theme={null}
from fastapi import Depends

from auth import authenticate_user
from models import User
```

Add the following endpoints.

```python theme={null}
@app.get("/public")
def public():
    return {
        "message": "This is a public endpoint."
    }


@app.get("/protected")
def protected(
    user: User = Depends(authenticate_user)
):
    return {
        "message": f"Welcome {user.username}!"
    }
```

### How It Works

The `/public` endpoint is accessible to everyone.

The `/protected` endpoint depends on the `authenticate_user()` dependency. Before executing the endpoint, FastAPI:

1. Reads the JWT from the `Authorization` header.
2. Validates the JWT signature.
3. Checks whether the token has expired.
4. Retrieves the authenticated user.
5. Executes the endpoint only if authentication succeeds.

### Run the Application

```bash theme={null}
uv run uvicorn app:app --reload
```

### Test the APIs

Open the Swagger UI.

```text theme={null}
http://127.0.0.1:8000/docs
```

#### Step 1 - Register

Register a new user.

```http theme={null}
POST /register
```

#### Step 2 - Login

Login to receive a JWT.

```http theme={null}
POST /login
```

Copy the returned `access_token`.

#### Step 3 - Authorize

Click the **Authorize** button in Swagger UI.

Enter the token in the following format:

```text theme={null}
Bearer <access_token>
```

Example:

```text theme={null}
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

Click **Authorize**.

#### Step 4 - Access the Protected Endpoint

Call:

```http theme={null}
GET /protected
```

If the token is valid, the response will be:

```json theme={null}
{
    "message": "Welcome john!"
}
```

If the token is missing, invalid, or expired, the response will be:

```http theme={null}
401 Unauthorized

### Expected Outcome

At the end of this task, you should have:

- A public endpoint accessible to everyone.
- A protected endpoint requiring a valid JWT.
- A complete implementation of JWT-based authentication.
```
