Saltar al contenido principal
Requisitos previos: Antes de comenzar, asegúrate de tener instalado lo siguiente:
  • Python 3.9 o una versión posterior
  • pip o el gestor de paquetes Poetry
  • jq - Necesario para configurar Auth0 CLI
  • Tu editor de código preferido
Compatibilidad de versiones de Flask: Esta guía de inicio rápido requiere Flask 3.0 o una versión posterior para el soporte nativo de async.

Primeros pasos

Esta guía muestra cómo integrar Auth0 con cualquier API de Python, nueva o existente, creada con Flask.
1

Crea un nuevo proyecto de Flask

Crea un directorio nuevo para tu API de Flask:
mkdir flask-auth0-api
cd flask-auth0-api
Cree un entorno virtual y actívelo:
python -m venv venv
source venv/bin/activate  # En Windows: venv\Scripts\activate
2

Instala las dependencias

Crea un archivo requirements.txt con las siguientes dependencias:
requirements.txt
flask>=3.0
auth0-api-python
python-dotenv
Instala las dependencias:
pip install -r requirements.txt
3

Configura tu API de Auth0

A continuación, debes crear una nueva API en tu inquilino de Auth0 y configurar tu aplicación.Puedes hacerlo automáticamente ejecutando un comando de la CLI o manualmente desde el Dashboard:
  1. Ve a Auth0 DashboardApplicationsAPIs
  2. Haz clic en Create API
  3. Introduce los datos de tu API:
    • Name: My Flask API
    • Identifier: https://my-flask-api (esta será tu audiencia)
    • Signing Algorithm: RS256
  4. Haz clic en Create
  5. Copia tu Domain desde el Dashboard (se encuentra en ApplicationsApplications[Your App]Settings)
  6. Copia el Identifier que acabas de crear (esta es tu audiencia)
Tu Domain no debe incluir https://; usa solo el nombre de dominio (por ejemplo, your-tenant.auth0.com).La Audiencia (identificador de la API) es un identificador único para tu API y puede ser cualquier URI válida.
4

Definir permisos de la API

Configure los permisos (alcances) de su API para controlar el acceso a recursos específicos:
  1. En el Auth0 Dashboard, vaya a ApplicationsAPIs
  2. Seleccione su API (My Flask API)
  3. Vaya a la pestaña Permissions
  4. Haga clic en Add Permission
  5. Agregue el siguiente permiso:
    • Permission (Scope): read:messages
    • Description: Read messages
  6. Haga clic en Add
Los permisos definen qué acciones se pueden realizar en su API. Puede agregar varios permisos, como write:messages, delete:messages, etc. El endpoint /api/private-scoped de esta guía de inicio rápido requiere el permiso read:messages.
5

Configura el cliente de Auth0

Si usaste el método de CLI en el paso 3, el archivo .env se creó automáticamente. Pasa directamente a crear el archivo app.py a continuación.
Si usaste el método del Dashboard, crea un archivo .env en la raíz del proyecto para almacenar la configuración de Auth0:
.env
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://my-flask-api
Reemplace your-tenant.us.auth0.com por su dominio de Auth0 real y actualice API_IDENTIFIER para que coincida con el identificador de su API en el Dashboard.
Cree un archivo app.py y configure el cliente de la API de Auth0:
app.py
import os
import asyncio
from flask import Flask, request, jsonify, g
from functools import wraps
from dotenv import load_dotenv
from auth0_api_python import ApiClient, ApiClientOptions
from auth0_api_python.errors import BaseAuthError

# Cargar variables de entorno
load_dotenv()

app = Flask(__name__)

# Inicializar el cliente de la API de Auth0 (singleton - creado una sola vez)
api_client = ApiClient(ApiClientOptions(
    domain=os.getenv("AUTH0_DOMAIN"),
    audience=os.getenv("AUTH0_AUDIENCE")
))
5

Crear rutas protegidas

Agregue un decorador para proteger las rutas y cree endpoints públicos y privados:
app.py
# Decorador de autenticación
def require_auth(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        auth_header = request.headers.get("Authorization", "")
        
        if not auth_header.startswith("Bearer "):
            return jsonify({"error": "Missing or invalid authorization header"}), 401
        
        token = auth_header.split(" ")[1]
        
        try:
            claims = asyncio.run(api_client.verify_access_token(token))
            g.user_claims = claims
            return f(*args, **kwargs)
        except BaseAuthError as e:
            return (
                jsonify({"error": str(e)}),
                e.get_status_code(),
                e.get_headers()
            )
    
    return decorated_function


# Endpoint público - no requiere autenticación
@app.route("/api/public", methods=["GET"])
def public():
    return jsonify({"message": "This endpoint is public"})


# Endpoint protegido - requiere autenticación
@app.route("/api/private", methods=["GET"])
@require_auth
def private():
    return jsonify({
        "message": "This endpoint requires authentication",
        "user": g.user_claims.get("sub")
    })


# Endpoint protegido con validación de permisos
@app.route("/api/private-scoped", methods=["GET"])
@require_auth
def private_scoped():
    scopes = g.user_claims.get("scope", "").split()
    
    if "read:messages" not in scopes:
        return jsonify({"error": "Insufficient permissions"}), 403
    
    return jsonify({
        "message": "Private scoped endpoint - read:messages permission granted",
        "user": g.user_claims.get("sub")
    })


if __name__ == "__main__":
    app.run(debug=True, port=5000)
6

Ejecute la API

Inicia tu aplicación Flask:
python app.py
Tu API ya se está ejecutando en http://localhost:5000.
Punto de controlAhora debería tener una API de Flask protegida con Auth0, totalmente funcional, ejecutándose en localhost con tres endpoints:
  • /api/public - Accesible sin autenticación
  • /api/private - Requiere un token de acceso válido de Auth0
  • /api/private-scoped - Requiere autenticación y el permiso read:messages

Prueba tu API

Para probar tus endpoints protegidos, necesitas un token de acceso.

Obtén un token de prueba

  1. Ve al Auth0 Dashboard
  2. Ve a Applications → APIs
  3. Selecciona tu API
  4. Ve a la pestaña Test
  5. Copia el token de acceso

Haz una solicitud

Prueba el endpoint público (no se requiere ningún token):
curl http://localhost:5000/api/public
Pruebe el endpoint protegido (requiere un token):
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  http://localhost:5000/api/private
Sustituya YOUR_ACCESS_TOKEN por el token que copió del Auth0 Dashboard.

Uso avanzado

Exija que el token de acceso incluya claims específicos:
try:
    claims = await api_client.verify_access_token(
        access_token=token,
        required_claims=["email_verified", "org_id"]
    )
except BaseAuthError as e:
    return jsonify({"error": "Faltan claims obligatorios"}), 401
Para reforzar la seguridad, habilite DPoP (Demonstrating Proof-of-Possession). DPoP mejora OAuth 2.0 al vincular los tokens de acceso a claves criptográficas.
import asyncio


# Configure el cliente de API con DPoP habilitado (modo Allowed)
api_client = ApiClient(ApiClientOptions(
    domain=os.getenv("AUTH0_DOMAIN"),
    audience=os.getenv("AUTH0_AUDIENCE"),
    dpop_enabled=True,   # Valor predeterminado: habilita la compatibilidad con DPoP
    dpop_required=False  # Valor predeterminado: permite tokens Bearer y DPoP
))

# Para el modo Required (solo DPoP, rechaza tokens Bearer)
# dpop_required=True

# Decorador compatible con DPoP
def require_auth_dpop(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        headers = {
            "authorization": request.headers.get("Authorization", ""),
            "dpop": request.headers.get("DPoP", "")  # Encabezado de prueba DPoP
        }
        
        try:
            # verify_request() detecta automáticamente el esquema Bearer o DPoP
            claims = asyncio.run(api_client.verify_request(
                headers=headers,
                http_method=request.method,
                http_url=request.url
            ))
            g.user_claims = claims
            return f(*args, **kwargs)
        except BaseAuthError as e:
            return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()
    
    return decorated_function

@app.route("/api/dpop-protected")
@require_auth_dpop
def dpop_protected():
    return jsonify({
        "message": "Autenticación correcta con DPoP o Bearer",
        "user": g.user_claims.get("sub")
    })
El método verify_request() detecta automáticamente si la solicitud usa autenticación Bearer o DPoP. Cuando se usa DPoP, valida tanto el token de acceso como la prueba DPoP conforme a RFC 9449.
Cree un decorador para comprobar alcances específicos:
def require_scope(required_scope):
    def decorator(f):
        @wraps(f)
        async def wrapper(*args, **kwargs):
            if not hasattr(g, "user_claims"):
                return jsonify({"error": "No autorizado"}), 401
            
            scopes = g.user_claims.get("scope", "").split()
            
            if required_scope not in scopes:
                return jsonify({"error": "Permisos insuficientes"}), 403
            
            return await f(*args, **kwargs)
        return wrapper
    return decorator


@app.route("/api/admin")
@require_auth
@require_scope("admin:write")
async def admin_endpoint():
    return jsonify({"message": "Acceso de administrador concedido"})
Implemente un manejo integral de errores con tipos de error específicos:
from auth0_api_python.errors import (
    BaseAuthError,
    VerifyAccessTokenError,
    GetTokenByExchangeProfileError,
    ApiError
)

@app.errorhandler(BaseAuthError)
def handle_auth_error(error):
    """Gestiona todos los errores de autenticación de Auth0"""
    return jsonify({
        "error": error.get_error_code(),
        "error_description": str(error)
    }), error.get_status_code(), error.get_headers()


@app.errorhandler(VerifyAccessTokenError)
def handle_token_verification_error(error):
    """Gestiona específicamente los errores de verificación de tokens"""
    app.logger.warning(f"La verificación del token falló: {str(error)}")
    return jsonify({
        "error": "invalid_token",
        "error_description": str(error)
    }), 401, error.get_headers()


@app.errorhandler(ApiError)
def handle_api_error(error):
    """Gestiona los errores de la API de Auth0 (red, límites de tasa, etc.)"""
    app.logger.error(f"Error de la API de Auth0: {error.code} - {error.message}")
    return jsonify({
        "error": error.code,
        "error_description": error.message
    }), error.status_code or 500


@app.errorhandler(Exception)
def handle_generic_error(error):
    """Captura cualquier error inesperado"""
    app.logger.error(f"Error inesperado: {str(error)}", exc_info=True)
    return jsonify({"error": "Error interno del servidor"}), 500
Todos los errores de autenticación heredan de BaseAuthError, que proporciona métodos como get_status_code(), get_headers() y get_error_code() para devolver respuestas HTTP correctas con encabezados WWW-Authenticate.
En aplicaciones en las que la mayoría de los endpoints requieren autenticación, use before_request de Flask para validar tokens de forma global:
from flask import g

PUBLIC_ROUTES = ["/api/public", "/health"]

@app.before_request
async def verify_token():
    # Omitir la autenticación en las rutas públicas
    if request.path in PUBLIC_ROUTES:
        return
    
    auth_header = request.headers.get("Authorization", "")
    
    if not auth_header.startswith("Bearer "):
        return jsonify({"error": "Falta la autorización"}), 401
    
    token = auth_header.split(" ")[1]
    
    try:
        claims = await api_client.verify_access_token(token)
        g.user_claims = claims
    except BaseAuthError as e:
        return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()


@app.route("/api/protected-data")
async def protected_data():
    # Claims disponibles automáticamente a través de g.user_claims
    return jsonify({"user_id": g.user_claims["sub"]})

Problemas comunes

Síntoma: Se producen errores 401 incluso con tokens que parecen válidosCausa: La audiencia del token no coincide con la audiencia configurada en el cliente de tu APISolución:
  1. Verifica que AUTH0_AUDIENCE en tu archivo .env coincida exactamente con el Identificador de API de Auth0
  2. La audiencia distingue entre mayúsculas y minúsculas
  3. Asegúrate de que la audiencia tenga formato de URL o URN (por ejemplo, https://my-api, no my-api)
Síntoma: La validación del token falla porque el emisor no coincideCausa: La configuración del dominio no coincide con el emisor del tokenSolución:
  1. Verifica que AUTH0_DOMAIN sea correcto (por ejemplo, tenant.us.auth0.com)
  2. No incluyas https:// en el dominio
  3. No incluyas una barra diagonal al final
Síntoma: Valores None o errores de variables de entornoCausa: Las variables de entorno no se cargaron o no se encontró el archivo .envSolución:
  1. Asegúrate de que el archivo .env exista en la raíz de tu proyecto
  2. Verifica que se llame a load_dotenv() antes de acceder a os.getenv()
  3. Comprueba que los nombres de las variables coincidan exactamente (distinguen entre mayúsculas y minúsculas)
Síntoma: RuntimeError: This event loop is already running u otros errores async similaresCausa: Usar rutas async sin Flask 3.0+ o mezclar sync y async de forma incorrectaSolución:
  1. Actualiza a Flask 3.0 o superior: pip install --upgrade flask
  2. Asegúrate de que todos los controladores de ruta que usan api_client estén declarados como async def
  3. No uses asyncio.run() dentro de los controladores de ruta
Síntoma: VerifyAccessTokenError: Token is expiredCausa: El token de acceso ya superó su tiempo de expiraciónSolución:
  1. Solicita un token nuevo desde la pestaña Test de Auth0 Dashboard
  2. Implementa la renovación de tokens en tu aplicación cliente
  3. Los tokens del Dashboard suelen ser válidos durante 24 horas
Síntoma: Error Missing or invalid authorization headerCausa: La solicitud no incluye el encabezado Authorization o usa un formato incorrectoSolución:
  1. Asegúrate de que el encabezado se llame Authorization (A mayúscula)
  2. Usa el formato: Authorization: Bearer YOUR_TOKEN
  3. No incluyas comillas alrededor del token

Recursos adicionales

Documentación del SDK

Documentación completa del SDK y referencia de la API

Documentación de Flask

Documentación oficial del framework Flask

Auth0 Dashboard

Gestiona tu inquilino de Auth0 y tus API

Guía de autenticación de API

Más información sobre los tokens de acceso y la seguridad de las API

Documentación de DPoP

Más información sobre la seguridad basada en prueba de posesión

Foro de la comunidad

Obtén ayuda de la comunidad de Auth0

Próximos pasos

Consulta el repositorio de ejemplos de la API de Auth0 para Python para ver ejemplos funcionales completos con Flask.