Lección 10 de 25 · Lectura y práctica
Quiz: Seguridad y Autenticación en FastAPI
Tipo de lección: QuizConcepto claveLa seguridad en APIs modernas se basa en tres pilares fundamentales: autenticación (verificar quién eres), autorización (qué puedes hacer) y protección de datos (cómo se maneja la información.
Del concepto a la práctica
Taller de esta lección
Usa una matriz de decisión para comprobar seguridad: identidad válida, permiso suficiente, entrada válida y recurso existente. Cada dimensión debe tener un resultado observable. La matriz evita confundir autenticación con autorización y permite revisar que un error temprano no filtre datos.
Ejemplo resuelto
Para editar el artículo 31: token ausente produce 401; token válido sin permiso produce 403; permiso válido con cuerpo incorrecto produce 422; todo correcto produce 200.
Pruébalo
Escribe las cuatro filas de la matriz, cambiando una sola condición cada vez; el token ausente se prueba con cuerpo válido y el cuerpo incorrecto con token y permiso válidos.
Asigna un usuario y artículo concretos.
Ejecuta una petición por fila.
Comprueba cuerpo, código y ausencia de escritura en fallos.
Comprueba tu resultado
La secuencia esperada es 401, 403, 422 y 200, con el artículo cambiado solo en la última fila.
Error frecuente: responder 200 con un mensaje de error. Corrígelo usando códigos HTTP coherentes y una prueba que falle si el código es incorrecto.

Mapa de prácticaEl control de acceso, las actualizaciones y las copias de seguridad cubren riesgos distintos. Una alerta necesita un procedimiento de respuesta para contener y recuperar el servicio. Varias capas reducen la exposición, pero ninguna garantiza seguridad absoluta.
Ver la infografía en tamaño completo ↗Tipo de lección: Quiz
Concepto clave
La seguridad en APIs modernas se basa en tres pilares fundamentales: autenticación (verificar quién eres), autorización (qué puedes hacer) y protección de datos (cómo se maneja la información sensible). En FastAPI, esto se implementa mediante middlewares, dependencias y estándares como OAuth2 con JWT.
Imagina una empresa con acceso controlado: primero muestras tu credencial (autenticación), luego el sistema verifica a qué áreas tienes permiso (autorización), y finalmente asegura que no puedas ver información confidencial de otros departamentos (protección de datos). FastAPI proporciona herramientas nativas para construir este flujo de manera eficiente y escalable.
Cómo funciona en la práctica
El proceso típico en FastAPI sigue estos pasos:
- El cliente envía credenciales (usuario/contraseña) a un endpoint de login
- El servidor valida las credenciales contra una base de datos
- Si son válidas, genera un token JWT firmado
- El cliente incluye este token en el header Authorization de solicitudes posteriores
- FastAPI valida automáticamente el token usando dependencias
- Se verifica si el usuario tiene permisos para la acción solicitada
Este flujo permite stateless authentication, ideal para arquitecturas microservicios.
Código en acción
Implementación básica de autenticación JWT:
from datetime import datetime, timedelta
from typing import Optional
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
# Configuración
SECRET_KEY = "tu_clave_secreta_super_segura"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
app = FastAPI()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
# Función para verificar contraseña
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# Función para crear token
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# Dependencia para obtener usuario actual
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
return token_data
@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
# Aquí iría la validación real contra base de datos
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"}
@app.get("/users/me")
async def read_users_me(current_user: TokenData = Depends(get_current_user)):
return {"username": current_user.username}Implementación mejorada con roles y permisos:
from enum import Enum
from fastapi import Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
class Role(str, Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"
security = HTTPBearer()
def has_permission(required_role: Role):
async def permission_dependency(
credentials: HTTPAuthorizationCredentials = Security(security)
):
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_role = payload.get("role")
# Jerarquía de permisos
role_hierarchy = {Role.GUEST: 1, Role.USER: 2, Role.ADMIN: 3}
if role_hierarchy.get(Role(user_role), 0) < role_hierarchy[required_role]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Insufficient permissions"
)
return payload
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token"
)
return permission_dependency
@app.get("/admin/dashboard")
async def admin_dashboard(
user_data = Depends(has_permission(Role.ADMIN))
):
return {"message": "Welcome to admin dashboard", "user": user_data}Errores comunes
- No validar expiración de tokens: Los tokens JWT deben tener expiración configurada y validarse en cada request. Sin esto, un token robado es válido indefinidamente.
- Almacenar secretos en código: Claves secretas como SECRET_KEY deben estar en variables de entorno, nunca hardcodeadas en el código fuente.
- Falta de rate limiting: Endpoints de login deben tener límites de intentos para prevenir ataques de fuerza bruta.
- No usar HTTPS en producción: Sin HTTPS, tokens viajan en texto plano, exponiéndolos a interceptación.
- Permisos demasiado amplios: Asignar permisos de administrador por defecto o no implementar principio de menor privilegio.
Checklist de dominio
- Implementé autenticación JWT con expiración configurable
- Protegí endpoints con dependencias que validan tokens automáticamente
- Implementé sistema de roles y permisos con jerarquía
- Configuré variables de entorno para claves secretas
- Agregué rate limiting a endpoints críticos
- Validé que todos los tokens incluyan claim "exp"
- Documenté los flujos de autenticación en OpenAPI/Swagger
Implementa un sistema de autenticación con refresh tokens
En este ejercicio, mejorarás el sistema de autenticación básico para incluir refresh tokens, una práctica esencial en APIs profesionales.
- Crea un nuevo endpoint
/refreshque acepte un refresh token válido y devuelva un nuevo access token - Modifica el endpoint
/tokenpara que devuelva tanto access_token como refresh_token - Implementa lógica para invalidar refresh tokens cuando sean comprometidos
- Asegúrate que los refresh tokens tengan mayor tiempo de expiración que los access tokens (ej: 7 días vs 30 minutos)
- Crea un endpoint
/logoutque permita invalidar ambos tokens - Agrega validación para prevenir reuso de refresh tokens
Entrega: Código completo con los 3 endpoints funcionando y pruebas que demuestren el flujo completo.
Pistas
- Considera almacenar refresh tokens en una base de datos para poder invalidarlos
- Usa diferentes claves secretas para access y refresh tokens
- Implementa blacklist para tokens invalidados
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.
Sigue con Dominio Profesional de FastAPI: Construcción de APIs Escalables y Seguras
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.