Angular solo habla con el dominio principal del sitio. No guarda credenciales privadas del backend.
Angular · Nginx · FastAPI · Seguridad
Configuración recomendada para que una API no quede expuesta al frontend publico
Cuando una aplicación Angular habla directamente con un backend, cualquier credencial que viaje al navegador termina expuesta. La solución correcta no es esconder mejor la clave, sino mover la confianza al lado servidor.
Esta guía resume el patrón aplicado: Angular llama al dominio principal de la web, Nginx reenvia la petición a una API privada y FastAPI solo acepta peticiones que lleguen con una cabecera interna inyectada por el proxy.
Un secreto solo es secreto si nunca llega al navegador. Si Angular lo envia, el secreto ya se ha perdido.
1. Por que el login directo desde frontend es mala idea
Una cuenta técnica compartida dentro del bundle del frontend puede extraerse del JavaScript compilado, del panel de red o del propio código fuente. Eso significa que el backend queda publico de facto aunque exija token.
Este problema aparece mucho cuando el frontend pide un token con usuario y contraseña fijos y luego reutiliza ese bearer en todas las peticiones.
2. Arquitectura recomendada
La solución practica consiste en separar el flujo entre frontend publico, reverse proxy confiable y API protegida.
Nginx añade una cabecera interna que solo existe en el lado servidor.
FastAPI rechaza llamadas directas salvo que la cabecera interna coincida con el secreto esperado.
La API sigue sirviendo a la web, pero ya no puede reutilizarse directamente por terceros solo con abrir DevTools.
3. Flujo recomendado en Nginx
Una forma limpia de exponer la funcionalidad es publicar una ruta dedicada como /api/servicio-interno/ en el dominio principal y redirigirla al host privado de la API.
server {
server_name example.com;
location ^~ /api/internal-service/ {
proxy_pass https://api-interna.example.com/;
proxy_http_version 1.1;
proxy_set_header Host api-interna.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Internal-Api-Key example.internal.key.please.change;
}
location / {
proxy_pass http://frontend_ssr;
}
}4. Validacion en FastAPI
El backend debe validar una cabecera interna contra una variable de entorno. El navegador nunca conoce ese valor; solo Nginx.
import os
import secrets
from fastapi import Depends, Header, HTTPException, status
INTERNAL_API_KEY = os.getenv("INTERNAL_API_KEY", "")
def require_internal_api_key(x_internal_api_key: str | None = Header(default=None)) -> None:
if not INTERNAL_API_KEY:
raise HTTPException(status_code=500, detail="INTERNAL_API_KEY is missing")
if not x_internal_api_key or not secrets.compare_digest(x_internal_api_key, INTERNAL_API_KEY):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Forbidden")
@app.get("/api/data")
def get_data(_: None = Depends(require_internal_api_key)):
return {"status": "ok"}5. Que debe hacer Angular
Angular debe consumir la ruta proxy del dominio publico y eliminar cualquier usuario, contraseña, bearer bootstrap o intercambio técnico de tokens.
Dicho de otra forma, Angular usa el servicio, pero no forma parte del perimetro de confianza.
export const environment = {
production: true,
backendApiBaseUrl: 'https://example.com/api/internal-service'
};
this.http.get(`${environment.backendApiBaseUrl}/api/data`).subscribe({
next: (response) => {
this.data = response;
},
error: (error) => {
this.errorMessage = 'The request could not be completed.';
}
});6. Como verificar que la configuración es correcta
La comprobación más útil es probar las dos rutas: la ruta publica proxy debe funcionar y la ruta directa de la API privada debe devolver 403.
curl -i https://example.com/api/internal-service/api/data
# Expected: 200
curl -i https://api-interna.example.com/api/data
# Expected: 4037. Checklist de despliegue
Usar una INTERNAL_API_KEY larga y aleatoria en el entorno del backend.
Configurar Nginx en el dominio publico para inyectar esa misma cabecera.
Mantener el dominio privado de la API sin esa cabecera inyectada.
Apuntar Angular en producción a la ruta publica proxy, no al host privado de la API.
Verificar que la ruta publica proxy responde 200 y la ruta directa privada responde 403.
Errores habituales
Inyectar el mismo secreto desde Angular o guardarlo en ficheros de entorno que llegan al navegador.
Reutilizar un /api ya ocupado en vez de crear un namespace dedicado como /api/crypto/.
Olvidar los file replacements y enviar URLs localhost a produccion.
Creer que CORS o esconder botones equivale a proteccion backend.
Cuando es recomendable este patron
Usalo cuando la web necesite la API pero no quieras publicar credenciales reutilizables ni permitir el uso directo del endpoint por terceros.
Si la API debe ser publica por definición, abrirla con buen rate limiting puede ser más simple. Si los datos dependen del usuario, entonces lo correcto es autenticación real por usuario.
Nota relacionada
Si el endpoint expone solo datos públicos, abrirlo con rate limiting puede ser más simple. Este patrón de proxy es útil cuando quieres que la web use la API pero no quieres acceso directo de terceros.