josedario87 e224f385d4
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 55s
Improve: Mejorar mensaje de alerta al salir del formulario
- Hacer el mensaje más claro y explicativo
- Enfatizar que los cambios NO se han enviado al servidor
- Indicar que quedarán guardados localmente en el navegador
- Agregar instrucción de cómo guardar definitivamente
- Iniciar con pregunta "¿Estás seguro de salir?"

Mensaje anterior era ambiguo, ahora es más específico sobre:
- Qué se guarda (localmente)
- Qué NO se guarda (en el servidor)
- Qué hacer para guardar definitivamente
2025-10-17 17:07:54 -06:00

Plantilla Nuxt + Authentik Proxy

Plantilla base para aplicaciones Nuxt 4 con autenticación mediante Authentik Proxy Outpost.

Estructura del Proyecto

.
├── nuxt4/              # Aplicación Nuxt 4
├── docker-compose.yml  # Configuración de despliegue
└── .gitea/            # Gitea Actions CI/CD

Características

  • Nuxt 4
  • Autenticación con Authentik Proxy Outpost
  • Docker y Docker Compose
  • CI/CD con Gitea Actions
  • Traefik para proxy reverso y SSL
  • Claude Code hooks para monitoreo de Actions
  • Sin configuración OAuth necesaria (todo manejado por el proxy)

Desarrollo Local

cd nuxt4
npm install
npm run dev

Claude Code Hooks

Este proyecto incluye hooks de Claude Code para monitorear automáticamente las Gitea Actions.

Configuración Rápida:

  1. Crear token de Gitea:

    • Ve a tu instancia de Gitea → Settings → Applications
    • Genera un token con permisos repo
  2. Configurar token:

    echo "export GITEA_TOKEN='tu_token_aqui'" >> ~/.bashrc
    source ~/.bashrc
    
  3. Listo! Cuando Claude Code haga git push, automáticamente:

    • Monitoreará la Gitea Action
    • Te notificará cuando termine con información detallada
    • Te mostrará un link directo a los logs

📖 Ver documentación completa en .claude/hooks/README.md

Arquitectura de Componentes

Componentes de Autenticación

La aplicación utiliza componentes Vue modulares para manejar la autenticación:

1. UserAvatar (app/components/auth/UserAvatar.vue)

  • Muestra el avatar del usuario (generado por UI Avatars)
  • Información básica: nombre/username, email y UID
  • Se renderiza solo cuando el usuario está autenticado

2. UserMetadata (app/components/auth/UserMetadata.vue)

  • Card detallada con todos los metadatos del usuario
  • Muestra: username, email, nombre completo, UID y grupos
  • Incluye badges para visualizar los grupos del usuario

3. Botones de Acción (componentes individuales)

Cada botón es un componente independiente con su propia lógica:

  • SessionStatusButton: Verifica el estado de la sesión contra Authentik

    • Hace una petición a /api/auth/status
    • Muestra notificaciones toast con el resultado
    • Maneja casos offline y errores de conexión
  • ProfileButton: Redirige al perfil de usuario en Authentik

    • Abre el panel de usuario de Authentik en nueva pestaña
    • URL: {authentikUrl}/if/user/
  • LogoutButton: Cierra sesión en Authentik

    • Invalida la sesión en todas las aplicaciones
    • Redirige a: {authentikUrl}/flows/-/default/invalidation/
  • LoginButton: Fuerza re-autenticación

    • Recarga la página para activar el flujo de login de Authentik

Composable useAuthentik()

Composable centralizado para manejar autenticación (app/composables/useAuthentik.ts):

Funcionalidades:

  • Lee headers de Authentik en el servidor (SSR)
  • Almacena información del usuario en useState (compartido entre cliente/servidor)
  • Proporciona funciones reactivas: user, isAuthenticated
  • Métodos: logout(), goToProfile(), checkSessionStatus()

Headers leídos del Proxy:

X-authentik-username  // Nombre de usuario
X-authentik-email     // Email
X-authentik-name      // Nombre completo
X-authentik-groups    // Grupos (separados por |)
X-authentik-uid       // ID único del usuario

Despliegue

El proyecto incluye Gitea Actions que automáticamente:

  1. Construye la imagen Docker
  2. La sube al registro
  3. Despliega usando docker-compose

Variables Requeridas en Gitea

Para configurar el despliegue automático, ve a tu repositorio en Gitea:

  • Secrets: Settings > Actions > Secrets
  • Variables: Settings > Actions > Variables

Secrets (valores sensibles):

  • REGISTRY_USERNAME - Usuario del registro Docker
  • REGISTRY_PASSWORD - Contraseña del registro Docker

Variables (valores públicos):

  • REGISTRY_URL - URL del registro Docker (ej: gitea.nucleoriofrio.com)
    • El owner del repositorio se agrega automáticamente
    • Imagen final: REGISTRY_URL/owner/APP_NAME:latest
  • APP_NAME - Nombre de la aplicación (ej: mi-app) - usado para container, imagen y Traefik
  • APP_DOMAIN - Dominio de la aplicación (ej: miapp.ejemplo.com)
  • NUXT_PUBLIC_APP_URL - URL pública de la app (ej: https://miapp.ejemplo.com)

📄 Ver ejemplo completo en .env.example

Configuración de Traefik y Authentik

🔐 Cómo Funciona Authentik Proxy Outpost

Authentik Proxy Outpost actúa como un Forward Auth middleware que intercepta todas las peticiones antes de que lleguen a tu aplicación:

Usuario → Traefik → Authentik Forward Auth → Aplicación Nuxt
                         ↓ (si no auth)
                    Redirect a Login

Flujo de autenticación:

  1. Usuario hace petición → Traefik recibe la petición a tu dominio
  2. Traefik consulta Authentik → Envía la petición al middleware de Forward Auth
  3. Authentik valida sesión:
    • Con sesión válida: Authentik agrega headers con info del usuario y envía la petición a tu app
    • Sin sesión: Authentik redirige al usuario al flujo de login
  4. Tu app recibe la petición → Con headers de usuario ya inyectados (SSR)

Ventajas:

  • No necesitas implementar OAuth en tu app
  • La autenticación se maneja completamente fuera de tu código
  • Los headers llegan automáticamente en cada petición SSR
  • Funciona con cualquier framework (Nuxt, Next.js, PHP, etc.)

🚦 Configuración de Reglas de Traefik

El docker-compose.yml configura dos routers en Traefik para balancear seguridad y funcionalidad PWA:

Router 1: Rutas Públicas (Sin Autenticación) - Prioridad 100

# Rutas que NO requieren autenticación
- PathPrefix(`/manifest.webmanifest`)  # Manifest PWA
- PathPrefix(`/sw.js`)                 # Service Worker
- PathPrefix(`/workbox-`)              # Workbox (PWA)
- PathPrefix(`/icon-`)                 # Iconos de la app
- PathPrefix(`/apple-touch-icon`)      # Icono iOS
- PathPrefix(`/favicon.ico`)           # Favicon
- PathPrefix(`/robots.txt`)            # SEO
- PathPrefix(`/offline.html`)          # Página offline PWA
- PathPrefix(`/api/_nuxt_icon/`)       # API de iconos de Nuxt

Middlewares aplicados:

  • ${APP_NAME}-headers: Headers personalizados (X-Forwarded-Proto)
  • ${APP_NAME}-cors: Configuración CORS para recursos públicos

¿Por qué sin autenticación?

  • Los Service Workers necesitan acceso sin auth para funcionar offline
  • Los manifests PWA deben ser públicos para instalación
  • Prioridad 100 asegura que estas rutas se evalúen primero

Router 2: Aplicación Protegida (Con Autenticación) - Prioridad 10

# Todas las demás rutas (Host match)
Host(`${APP_DOMAIN}`)

Middlewares aplicados:

  • authentik-forward-auth@file: Forward Auth de Authentik
  • ${APP_NAME}-headers: Headers personalizados

Características:

  • Prioridad menor (10) → se evalúa después de las rutas públicas
  • Cualquier ruta no pública pasa por autenticación
  • Authentik inyecta headers con información del usuario

📋 Configuración de Authentik Proxy Outpost

Requisitos previos:

  • Traefik corriendo con las redes traefik-network y principal
  • Authentik instalado y funcionando

Pasos de configuración:

1. Crear el Middleware en Traefik

Crea o edita el archivo de configuración dinámica de Traefik (ej: dynamic/middlewares.yml):

http:
  middlewares:
    authentik-forward-auth:
      forwardAuth:
        address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-authentik-username
          - X-authentik-groups
          - X-authentik-email
          - X-authentik-name
          - X-authentik-uid

Importante: Cambia authentik-server por el nombre de tu contenedor/servicio de Authentik.

2. Configurar Authentik

a) Crear un Proxy Provider:

  • Ve a Admin > Applications > Providers
  • Click en Create
  • Tipo: Proxy Provider
  • Configuración:
    • Name: Mi App - Forward Auth
    • Authorization flow: Selecciona tu flujo (ej: default-provider-authorization-implicit-consent)
    • Type: Forward auth (single application)
    • External host: https://miapp.ejemplo.com (tu dominio)

b) Crear una Application:

  • Ve a Admin > Applications > Applications
  • Click en Create
  • Configuración:
    • Name: Mi App
    • Slug: mi-app
    • Provider: Selecciona el provider creado arriba

c) Vincular al Outpost:

  • Ve a Admin > Outposts > Outposts
  • Edita tu Outpost (o crea uno nuevo si no existe)
  • En Applications: Agrega la aplicación creada

3. Configurar las Redes en Docker Compose

Tu aplicación necesita estar en ambas redes:

networks:
  principal:           # Red de tu infraestructura
    external: true
  traefik-network:     # Red donde corre Traefik
    external: true

Asegúrate de que estas redes existan:

docker network create principal
docker network create traefik-network

🔍 Headers Disponibles en tu Aplicación

Una vez configurado, Authentik inyecta estos headers en cada petición:

Header Descripción Ejemplo
X-authentik-username Nombre de usuario nucleo000
X-authentik-email Email del usuario user@example.com
X-authentik-name Nombre completo John Doe
X-authentik-groups Grupos (separados por |) admins|users
X-authentik-uid ID único del usuario 703cae063c59...

En Nuxt, estos headers se leen automáticamente en SSR mediante useRequestHeaders().

🐛 Troubleshooting

Problema: "Cannot find name 'process'"

  • Usa import.meta.server en lugar de process.server (Nuxt 4)

Problema: Redirect loop infinito

  • Verifica que el middleware authentik-forward-auth@file esté correctamente configurado
  • Revisa que la aplicación esté asociada al Outpost en Authentik
  • Comprueba que el External host coincida con tu dominio

Problema: Headers no llegan a la aplicación

  • Verifica que authResponseHeaders incluya todos los headers necesarios
  • Asegúrate de que estés leyendo headers en SSR (import.meta.server)

Problema: PWA no funciona offline

  • Verifica que las rutas públicas tengan prioridad 100
  • Confirma que /sw.js, /manifest.webmanifest y /offline.html estén en el router público

Licencia

MIT

Description
No description provided
Readme 2.2 MiB
Languages
Vue 66.6%
TypeScript 27.9%
Shell 2.8%
HTML 1.5%
CSS 0.9%
Other 0.3%