In the previous chapter, SQLModel Integration, we built a working database to store our "Heroes". However, we have a major problem: The doors are unlocked.
Right now, anyone who knows your API URL can add, delete, or modify data. In a real application, we need to know who is knocking at the door (Authentication) and check if they are allowed inside (Authorization).
Imagine you are running an exclusive club (your API).
FastAPI has a built-in security system based on OAuth2. While the name sounds complex, the concept is simple. It works exactly like a corporate office badge system.
FastAPI handles the "Scanner" part automatically using the Dependency Injection System we learned in Chapter 4.
First, we need to tell FastAPI where the "Login Office" is. We use OAuth2PasswordBearer.
from fastapi import FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
# This tells FastAPI: "To get a token, go to the URL /token"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
Explanation:
OAuth2PasswordBearer is a class that defines how we extract the security token.tokenUrl="token" is a configuration setting. It tells the automatic documentation (Swagger UI): "If the user wants to log in, send them to the /token route."Now, let's protect a route. We want to ensure that only people with a "Badge" (Token) can see our items.
We use Depends to inject the security scheme.
from fastapi import Depends
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
Explanation:
Authorization with a value like Bearer mysecrettoken.token is populated with "mysecrettoken".The scanner expects a token. But how does the user get one? We need a route to exchange a username and password for that token.
FastAPI provides a helper called OAuth2PasswordRequestForm to handle the login data.
from fastapi.security import OAuth2PasswordRequestForm
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
# In a real app, verify user/pass from DB here!
return {"access_token": form_data.username, "token_type": "bearer"}
Explanation:
OAuth2PasswordRequestForm: This is a dependency that reads username and password from the Form Data (not JSON) sent by the user.access_token and token_type.Usually, you don't just want the token string; you want to know which user owns that token.
We can create a powerful dependency called get_current_user.
# 1. This dependency gets the token string
def get_current_user(token: str = Depends(oauth2_scheme)):
# 2. In real life, decode the token to find the user ID
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(user: dict = Depends(get_current_user)):
return user
Explanation:
read_users_me asks for user.get_current_user.get_current_user asks for token (via oauth2_scheme).get_current_user -> which finds the user object -> which is passed to your route.
Because FastAPI uses the standard OpenAPI specification (Chapter 3), using these security tools adds a special feature to your /docs page.
You will see a green Authorize button.
FastAPI will automatically attach the "Badge" (Token) to every request you make in the documentation browser. You don't have to manually copy-paste headers!
How does OAuth2PasswordBearer actually work? It is simply a Dependency class that acts like a gatekeeper.
oauth2.py
The logic resides in fastapi/security/oauth2.py. It inherits from SecurityBase.
Here is a simplified version of the logic:
# Simplified concept from fastapi/security/oauth2.py
from starlette.requests import Request
from fastapi.exceptions import HTTPException
class OAuth2PasswordBearer:
def __init__(self, tokenUrl: str):
self.tokenUrl = tokenUrl
async def __call__(self, request: Request) -> str:
# 1. Get the header
authorization = request.headers.get("Authorization")
# 2. Check if it exists and starts with "Bearer"
if not authorization or not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Not authenticated")
# 3. return the token string
return authorization.split(" ")[1]
Explanation:
__call__: This magic method allows the class instance to be used as a function (a callable). This is why we can pass it to Depends().In this chapter, we secured our application using FastAPI's integrated tools.
Depends) to place this scanner in front of our routes.OAuth2PasswordRequestForm helps create a login endpoint.Now that our API is secure, we need to look at how to run code before or after a request is processed globally, such as for tracking performance or handling CORS headers.
Generated by Code IQ