0
0
FastapiHow-ToBeginner · 4 min read

How to Use OAuth2 in FastAPI: Simple Guide with Example

In FastAPI, you use OAuth2PasswordBearer to define the OAuth2 scheme and OAuth2PasswordRequestForm to handle user login. You create a token endpoint to issue access tokens and protect routes by requiring a valid token with Depends.
📐

Syntax

FastAPI provides built-in classes to handle OAuth2 password flow:

  • OAuth2PasswordBearer(tokenUrl="token"): Defines the URL where clients get the token.
  • OAuth2PasswordRequestForm: Parses form data for username and password during login.
  • Depends: Used to require the token in protected routes.
python
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    username = form_data.username
    password = form_data.password
    # Validate user and create token here
    return {"access_token": "fake-token", "token_type": "bearer"}

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    # Use token to get user info
    return {"token": token}
💻

Example

This example shows a simple OAuth2 password flow with a fake user check and token return. The /token endpoint accepts username and password, then returns a token. The /users/me endpoint requires a valid token to access.

python
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

fake_users_db = {
    "alice": {
        "username": "alice",
        "full_name": "Alice Wonderland",
        "hashed_password": "fakehashedsecret",
        "disabled": False,
    }
}

def fake_hash_password(password: str):
    return "fakehashed" + password

class User(BaseModel):
    username: str
    full_name: str | None = None
    disabled: bool | None = None

class UserInDB(User):
    hashed_password: str

async def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return UserInDB(**user_dict)

async def fake_decode_token(token: str):
    # This doesn't provide real security
    user = await get_user(fake_users_db, token)
    return user

async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = await fake_decode_token(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return user

async def get_current_active_user(current_user: User = Depends(get_current_user)):
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user_dict = fake_users_db.get(form_data.username)
    if not user_dict:
        raise HTTPException(status_code=400, detail="Incorrect username or password")
    user = UserInDB(**user_dict)
    hashed_password = fake_hash_password(form_data.password)
    if not hashed_password == user.hashed_password:
        raise HTTPException(status_code=400, detail="Incorrect username or password")
    return {"access_token": user.username, "token_type": "bearer"}

@app.get("/users/me", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_active_user)):
    return current_user
Output
Run the app and POST to /token with form data username=alice and password=secret to get a token. Use the token as Bearer in Authorization header to GET /users/me and receive user info.
⚠️

Common Pitfalls

  • Not setting tokenUrl correctly in OAuth2PasswordBearer causes token requests to fail.
  • Returning plain usernames as tokens is insecure; use JWT or other secure tokens in real apps.
  • Forgetting to include Depends(oauth2_scheme) in protected routes means no authentication is enforced.
  • Not handling token expiration or revocation can lead to security risks.
python
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()
# Wrong: tokenUrl does not match actual token endpoint
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="wrong-token-url")

@app.get("/protected")
async def protected_route(token: str = Depends(oauth2_scheme)):
    return {"token": token}

# Correct usage:
oauth2_scheme_correct = OAuth2PasswordBearer(tokenUrl="token")
📊

Quick Reference

OAuth2PasswordBearer: Defines the token URL clients use to get tokens.
OAuth2PasswordRequestForm: Parses username and password from form data.
Depends: Injects dependencies like token validation.
Token endpoint: Issues tokens after verifying credentials.
Protected routes: Require token via Depends(oauth2_scheme).

Key Takeaways

Use OAuth2PasswordBearer with the correct tokenUrl to define the OAuth2 scheme.
Create a token endpoint that validates user credentials and returns an access token.
Protect routes by requiring the token with Depends(oauth2_scheme).
Never use plain strings as tokens in production; use secure tokens like JWT.
Handle token expiration and user status to maintain security.