Skip to content

About

a lightweight prototype implementing user registration, secure password hashing, and jwt authentication in fastapi

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

11 Commits

Folders and files

Repository files navigation

FastAPI JWT Auth Prototype

A lightweight prototype implementing user registration, secure password hashing, and JSON Web Token (JWT) authentication in FastAPI.

Status: Prototype / Learning Project

Features

  • User registration
  • Password hashing with pwdlib
  • JWT-based access tokens
  • Short-lived access tokens
  • Opaque random refresh tokens
  • SHA-256 hashing of refresh tokens before database storage
  • Refresh-token rotation
  • Server-side refresh-session revocation
  • Logout
  • Protected routes
  • Password change for authenticated users
  • Forgot-password flow
  • Password-reset tokens
  • Password-reset token expiration and revocation
  • Automatic invalidation of existing sessions after password changes
  • password_changed_at support for invalidating previously issued JWTs

Authentication Flow

Login

Client
  │
  │ POST /auth/login
  ▼
FastAPI
  │
  ├── Verify email
  ├── Verify password
  │
  ├── Generate JWT access token
  │
  └── Generate opaque refresh token
          │
          └── Store SHA-256 hash in database
  ▼
Client receives:
  ├── access_token
  └── refresh_token

Access token

The access token is a JWT containing the user's ID as the sub claim.

Example payload:

{
  "sub": "123",
  "iat": 1750000000,
  "exp": 1750000900
}

The access token is used to access protected endpoints:

Authorization: Bearer <access_token>

Refresh token

Refresh tokens are opaque random tokens, not JWTs.

The actual token is given to the client, while only its SHA-256 hash is stored in the database.

Refresh token
     │
     ▼
SHA-256 hash
     │
     ▼
Database

This means the database does not contain the usable refresh token.

Refresh-token rotation

Every successful refresh invalidates the old session and creates a new one:

RT1
 │
 │ POST /auth/refresh
 ▼
RT1 → revoked
RT2 → created

The client must replace its old refresh token with the newly issued one.

Password Security

Passwords are never stored directly.

During registration/password changes:

plain password
    │
    ▼
password hashing
    │
    ▼
password_hash
    │
    ▼
database

Password verification is performed against the stored hash during login or password changes.

Password Change / Reset

There are two separate flows.

Change password

Used when the user is already authenticated:

POST /auth/change-password

Requires:

  • current password
  • new password
  • password confirmation
  • valid access token

After changing the password:

  1. password_changed_at is updated.
  2. Existing refresh-token sessions are revoked.
  3. Previously issued access tokens are rejected by get_current_user.

Forgot password

POST /auth/forgot-password

The user provides their email.

The server generates a random password-reset token and stores only its hash.

Reset token
    │
    ├── sent to user
    │
    └── SHA-256 hash → database

The token expires after the configured reset-token lifetime.

Reset password

POST /auth/reset-password

The user provides:

{
  "token": "...",
  "new_password": "...",
  "confirm_password": "..."
}

After a successful reset:

  • password is changed
  • password_changed_at is updated
  • reset token is revoked
  • existing refresh sessions are revoked

Logout

POST /auth/logout

Logout uses the refresh token to identify the user's server-side session.

The corresponding Session record is marked:

revoked_at = current_time

The refresh token can no longer be used to obtain new access tokens.

API Endpoints

Method Endpoint Authentication Description
POST /auth/register None Register a new user
POST /auth/login None Login and obtain tokens
POST /auth/refresh Refresh token Rotate refresh token and obtain a new access token
POST /auth/logout Refresh token Revoke the current session
GET /auth/me Access token Get the authenticated user
POST /auth/forgot-password None Request a password reset
POST /auth/reset-password Reset token Set a new password
POST /auth/change-password Access token Change the current password

Environment Variables

Create a .env file:

DATABASE_URL=postgresql+psycopg://user:pass@localhost:5432/test_db
SECRET_KEY=your-secret-key
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_MINUTES=20000
PASSWORD_RESET_TOKEN_EXPIRE_MINUTES=15

Do not commit your .env file to version control.

Running the Project

Assuming PostgreSQL is already set up. Navigate to project directory.

Then:

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
rm -rf alembic/versions/
alembic revision --autogenerate -m "create db tables"
alembic upgrade head

Start the development server:

uvicorn main:app --reload

The API will be available at:

http://localhost:8000

Interactive API documentation:

http://localhost:8000/docs

About

a lightweight prototype implementing user registration, secure password hashing, and jwt authentication in fastapi

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages