0
0
FastapiHow-ToBeginner · 4 min read

How to Create a Login Endpoint in FastAPI Quickly

To create a login endpoint in FastAPI, define a POST route that accepts user credentials, verifies them, and returns an access token. Use OAuth2PasswordRequestForm to handle form data and fastapi.security utilities for token creation and validation.
📐

Syntax

The login endpoint in FastAPI typically uses a POST method with OAuth2PasswordRequestForm to receive username and password. You verify credentials, then return a token for authentication.

  • @app.post("/login"): Defines the login route.
  • OAuth2PasswordRequestForm: Parses form data for username and password.
  • Depends: Injects dependencies like the form data.
  • return: Sends back an access token and token type.
python
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordRequestForm

app = FastAPI()

@app.post("/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    username = form_data.username
    password = form_data.password
    # Verify username and password here
    access_token = "token_example"
    return {"access_token": access_token, "token_type": "bearer"}
💻

Example

This example shows a complete login endpoint that checks a hardcoded user and password, then returns a JWT token if valid. It uses passlib to hash passwords and PyJWT to create tokens.

python
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from passlib.context import CryptContext
import jwt
from datetime import datetime, timedelta

app = FastAPI()

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

fake_user_db = {
    "johndoe": {
        "username": "johndoe",
        "hashed_password": pwd_context.hash("secret123")
    }
}

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def authenticate_user(username: str, password: str):
    user = fake_user_db.get(username)
    if not user:
        return False
    if not verify_password(password, user["hashed_password"]):
        return False
    return user

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

@app.post("/login")
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",
            headers={"WWW-Authenticate": "Bearer"},
        )
    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"}
Output
When you POST username and password to /login, you get a JSON response with an access_token string and token_type "bearer".
⚠️

Common Pitfalls

  • Not hashing passwords before storing or verifying them, which is insecure.
  • Returning plain passwords or sensitive info in responses.
  • Not setting proper HTTP status codes like 401 for failed login.
  • Ignoring token expiration and refresh mechanisms.
  • Using GET instead of POST for login, which exposes credentials in URLs.
python
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordRequestForm

app = FastAPI()

# Wrong: Accepting password as plain text without hashing
@app.post("/login_wrong")
async def login_wrong(form_data: OAuth2PasswordRequestForm = Depends()):
    if form_data.username == "user" and form_data.password == "pass":
        return {"token": "fake-token"}
    return {"error": "Invalid credentials"}

# Right: Use hashed passwords and proper error handling
from fastapi import HTTPException, status

@app.post("/login_right")
async def login_right(form_data: OAuth2PasswordRequestForm = Depends()):
    # Imagine verify_password is implemented
    if form_data.username != "user" or form_data.password != "pass":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
    return {"access_token": "real-token", "token_type": "bearer"}
📊

Quick Reference

Remember these key points when creating a login endpoint in FastAPI:

  • Use POST method with OAuth2PasswordRequestForm to get username and password.
  • Always hash passwords before storing or verifying.
  • Return a JWT or similar token with expiration for authentication.
  • Use proper HTTP status codes like 401 for unauthorized access.
  • Keep your SECRET_KEY safe and never expose it.

Key Takeaways

Use POST with OAuth2PasswordRequestForm to securely receive login data.
Always hash and verify passwords; never store or compare plain text passwords.
Return a JWT token with expiration to authenticate users after login.
Handle failed logins with HTTP 401 Unauthorized status.
Keep your secret keys private and use secure token algorithms.