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
tokenUrlcorrectly inOAuth2PasswordBearercauses 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.