# 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 ```bash 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:** ```bash 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`](.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:** ```typescript 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`](.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 ```yaml # 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 ```yaml # 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`): ```yaml 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: ```yaml networks: principal: # Red de tu infraestructura external: true traefik-network: # Red donde corre Traefik external: true ``` Asegúrate de que estas redes existan: ```bash 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