In this tutorial we''re going to create an authentication system. We want to build our website, however, we don't want unauthenticated users to access the dashboard screen.
We will build our backend with Fast API, our Frontend with NextJS and the database will be SQLITE3.

Step 1: Set up the backend
Create your project folder and set up the FastAPI backend.
mkdir auth-project && cd auth-project mkdir backend && cd backend python -m venv venv source venv/bin/activate # on Windows: venv\Scripts\activate
Our backend needs external libraries for it to function fully. Inside the backend folder, create a file named requiremnts.txt and put the contents below inside:
fastapi==0.135.2 uvicorn==0.42.0 pydantic==2.12.5 passlib==1.7.4 bcrypt==4.0.1 python-jose==3.5.0 cryptography==46.0.6 python-multipart==0.0.22 starlette==1.0.0
So here, we've just defined our packages/dependencies/libraries. The next step is to install them into our environment. Run the command below in the terminal:
pip install -r requirements.txt
Inside the backend folder, create a main.py file:
from fastapi import HTTPException,FastAPI, Depends, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
import sqlite3
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
SECRET_KEY = "your-secret-key-change-this"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_c CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
# --- Database setup ---
def get_db():
c sqlite3.connect("users.db")
conn.row_factory = sqlite3.Row
return conn
def init_db():
c get_db()
conn.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
hashed_password TEXT NOT NULL
)
""")
conn.commit()
conn.close()
init_db()
# --- Schemas ---
class RegisterSchema(BaseModel):
username: str
email: str
password: str
class LoginSchema(BaseModel):
email: str
password: str
# --- Helpers ---
def hash_password(password: str):
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str):
return pwd_context.verify(plain, hashed)
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
# --- Routes ---
@app.get("/")
def read_root():
return {"Hello": "API is up and Running"}
@app.post("/register")
def register(user: RegisterSchema):
c get_db()existing = conn.execute("SELECT * FROM users WHERE email = ?", (user.email,)).fetchone()