FastAPI Security
How does FastAPI handle security?
FastAPI has built-in support for common security mechanisms like OAuth2, JWT (JSON Web Tokens), and HTTP Basic Authentication. It provides utilities for implementing security features such as access control, authentication, and authorization in a secure and simple way. FastAPI allows you to easily handle secure authentication and authorization using dependencies like OAuth2PasswordBearer and JWT for token-based authentication.
What is OAuth2PasswordBearer in FastAPI?
OAuth2PasswordBearer is a class in FastAPI used to handle OAuth2 authentication. It's part of OAuth2's "password flow" mechanism, which allows clients to send a username and password to get an access token. This token can then be used to authenticate subsequent requests. In FastAPI, it is used to extract the bearer token from the Authorization header of requests.
Example of using OAuth2PasswordBearer:
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
if token != "valid-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"token": token}
In this example, the token is extracted from the Authorization header using OAuth2PasswordBearer and validated before granting access to the route.
How do you implement JWT (JSON Web Tokens) authentication in FastAPI?
JWT (JSON Web Tokens) is commonly used for token-based authentication in web applications. FastAPI allows you to implement JWT-based authentication by generating a JWT token upon user login and validating that token in subsequent requests to protected routes.
Example of generating and verifying a JWT:
from datetime import datetime, timedelta
from jose import JWTError, jwt
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
SECRET_KEY = "secret"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def verify_token(token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise HTTPException(status_code=401, detail="Invalid token")
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
return username
@app.post("/token")
async def login():
access_token = create_access_token(data={"sub": "user_id"})
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
user = verify_token(token)
return {"username": user}
In this example, a JWT is generated upon user login, and the token is verified on each request to a protected route by decoding it and checking the payload for validity.
How do you secure routes using role-based access control (RBAC) in FastAPI?
To implement role-based access control (RBAC) in FastAPI, you can store user roles in JWT tokens or in the database and verify the role in your route dependencies. This allows you to protect routes based on the user's role (e.g., "admin", "editor", "user").
Example of role-based access control:
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import jwt
SECRET_KEY = "secret"
ALGORITHM = "HS256"
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def verify_token(token: str, required_role: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
role = payload.get("role")
if role != required_role:
raise HTTPException(status_code=403, detail="Insufficient permissions")
except jwt.JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/admin/")
async def read_admin_data(token: str = Depends(oauth2_scheme)):
verify_token(token, "admin")
return {"message": "Access granted to admin"}
In this example, the user's role is extracted from the JWT token, and access to the /admin/ route is restricted to users with the "admin" role.
How do you secure WebSockets in FastAPI?
FastAPI allows you to secure WebSocket connections in a similar way to HTTP routes. You can pass authentication tokens as query parameters or headers and validate them before accepting the WebSocket connection.
Example of securing WebSockets using a token:
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends
from jose import jwt
SECRET_KEY = "secret"
ALGORITHM = "HS256"
app = FastAPI()
async def verify_token(token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload.get("sub")
except jwt.JWTError:
raise WebSocketDisconnect()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str = Depends(verify_token)):
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message received: {data}")
except WebSocketDisconnect:
await websocket.close()
In this example, a token is passed via query parameters or headers to authenticate the WebSocket connection. If the token is invalid, the connection is closed.
How do you protect routes using HTTP Basic Authentication in FastAPI?
FastAPI provides a simple way to implement HTTP Basic Authentication using the HTTPBasic class. It requires the client to send a username and password with each request, and the server can validate those credentials before granting access.
Example of using HTTP Basic Authentication:
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
def authenticate_user(credentials: HTTPBasicCredentials):
correct_username = "user"
correct_password = "password"
if credentials.username != correct_username or credentials.password != correct_password:
raise HTTPException(status_code=401, detail="Invalid credentials")
@app.get("/secure-data/")
async def secure_data(credentials: HTTPBasicCredentials = Depends(security)):
authenticate_user(credentials)
return {"message": "You have access to secure data"}
In this example, HTTP Basic Authentication is used to secure the /secure-data/ route. The credentials are validated, and if they are correct, access is granted.
How do you secure FastAPI routes with API keys?
FastAPI supports securing routes using API keys by extracting the key from the request headers, query parameters, or cookies, and validating it. API keys are commonly used for authenticating clients in public APIs.
Example of securing a route with an API key:
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
API_KEY = "mysecretapikey"
async def verify_api_key(api_key: str):
if api_key != API_KEY:
raise HTTPException(status_code=403, detail="Invalid API key")
@app.get("/data/")
async def get_data(api_key: str = Depends(verify_api_key)):
return {"message": "Access granted with API key"}
In this example, the API key is extracted from the query parameters or headers, and if it matches the expected key, access is granted to the route.
How do you handle CORS in FastAPI for security?
FastAPI provides built-in support for Cross-Origin Resource Sharing (CORS) using the CORSMiddleware. CORS is a security feature that allows you to control which domains are permitted to access resources on your API from a different domain.
Example of configuring CORS in FastAPI:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allow all origins
allow_credentials=True,
allow_methods=["*"], # Allow all HTTP methods
allow_headers=["*"], # Allow all headers
)
In this example, CORS is configured to allow requests from all origins, methods, and headers. You can restrict it further by specifying allowed origins, methods, or headers for added security.