1. ¿Cuál era el objetivo del proyecto?
Históricamente, el Portal Ciudadano funcionaba como una isla con su propio sistema de contraseñas. Cada vez que el vecino ingresaba debía recordar credenciales distintas a las de otros sistemas municipales.
Antes
- Múltiples contraseñas dispersas en distintas plataformas.
- Contraseñas guardadas en la base de datos sin cifrado moderno.
- Sin posibilidad de inicio de sesión unificado municipal (SSO).
Ahora con Authentik
- Un solo usuario y contraseña para todos los servicios digitales del Municipio.
- Cifrado criptográfico automático de contraseñas de alta seguridad.
- Los vecinos conservan intactos sus inmuebles, rodados, boletas e historial.
2. ¿Cómo se realizó la integración? (Paso a Paso)
Incorporación y Cifrado de Ciudadanos
Se procesó la base histórica municipal (31.869 ciudadanos) cargándolos en una carpeta virtual dedicada llamada "Ciudadanos" en Authentik. De este modo, los vecinos quedan completamente organizados e independientes de las cuentas de empleados municipales. Además, sus contraseñas fueron automáticamente protegidas con cifrado seguro.
Conexión del Portal con Authentik
Se configuró el Portal Ciudadano para comunicarse directamente con Authentik utilizando el estándar internacional de identidad digital OpenID Connect (OIDC). El vecino solo presiona un botón y Authentik valida de forma segura quién es.
Reconocimiento Inteligente (Anti-Duplicación)
Cuando el ciudadano entra por primera vez con Authentik, el portal no crea un usuario duplicado. Busca de forma inteligente su CUIT, DNI o correo en la base histórica y enlaza su sesión con su cuenta existente. Así, el vecino no pierde ninguna boleta ni trámite anterior.
Cierre de Sesión Completo y Seguro
Al tocar "Cerrar sesión" en cualquier pantalla, se cierran tanto el portal como la sesión central de Authentik al mismo tiempo. Esto garantiza total privacidad y protección al usar computadoras compartidas o cabinas públicas.
3. Demostración en Vivo: Cómo Probar el Sistema
Cualquier autoridad o miembro del equipo puede verificar el funcionamiento ahora mismo desde su navegador:
Caso 1: Ciudadano con Perfil Activo
Acceso DirectoInicia sesión e ingresa directamente al panel principal del vecino con sus datos vinculados:
Caso 2: Ciudadano con Datos a Completar
Validación de PerfilInicia sesión y el sistema detecta que falta su domicilio, redirigiéndolo a completar perfil:
Guía rápida de comprobación:
- Hacé clic en "Probar este Usuario" o ingresá a http://192.168.10.154:8081.
- Presioná el botón azul "Iniciar sesión con Authentik" e ingresá las credenciales indicadas arriba.
- Verificá que el portal reconozca de inmediato al vecino y cargue su información.
- Hacé clic en "Cerrar sesión" en la barra superior para comprobar que la sesión se desactiva por completo en ambos sistemas.
4. Próxima Etapa: Integración con ARCA (AFIP) y Mi Argentina
Autenticación de Nivel 2 y 3 sin delegación de servicios ni fricción para el vecinoUna de las preguntas más frecuentes es si el vecino tiene que entrar al complejo "Administrador de Relaciones" de AFIP a adherir el servicio municipal. La respuesta es NO. Con Authentik actuando como Federador de Identidad (Identity Broker), el vecino únicamente ingresa su CUIT y Clave Fiscal en ARCA, y el sistema municipal recibe automáticamente su nivel de seguridad validado.
Simulador Interactivo del Recorrido de Credenciales
Simulador en espera
Presioná el botón "Simular ARCA (Nivel 2)" o "Simular Mi Argentina" arriba para ver cómo viajan los datos y cómo el portal valida los trámites sensibles de forma transparente.
Cero Fricción para el Vecino
El ciudadano no tiene que delegar servicios ni ingresar al Administrador de Relaciones de AFIP. Solo pone su CUIT y Clave Fiscal en la web oficial de ARCA.
Trámites con Nivel 2 o 3
ARCA devuelve a Authentik el campo nivel_seguridad: 2. El portal lo recibe y habilita automáticamente gestiones de alto impacto (débito automático, exenciones y libre deudas).
Trámite Único Municipal
El convenio de integración se tramita una sola vez entre el Municipio y ARCA. Una vez habilitado, todos los contribuyentes del país pueden usarlo sin pasos previos.
5. Documentación Técnica para el Área de Desarrollo
Arquitectura, archivos creados/modificados y flujo OpenID Connect (OIDC)Archivos Modificados y Creados en el Portal
| Archivo | Tipo | Descripción Técnica y Rol en el SSO |
|---|---|---|
authentik_login.php |
Nuevo | Genera el token criptográfico anti-CSRF (state) en la sesión PHP y redirige al navegador del ciudadano al endpoint de autorización de Authentik (/application/o/authorize/) solicitando los scopes openid profile email. |
authentik_callback.php |
Nuevo | Receptor central del flujo OIDC: Valida el parámetro state, intercambia el code por el access_token vía cURL POST contra /application/o/token/, consulta el endpoint /application/o/userinfo/ y ejecuta el algoritmo de fusión anti-duplicación (busca por CUIT $\to$ DNI $\to$ Email para asociar el id_usuario histórico). Inicializa las variables de sesión que el portal requiere ($_SESSION['tokenmuni'], $_SESSION['username']) y redirige a portal.php. |
cerrar_sesion.php |
Modificado | Single Logout (SLO): Destruye la sesión PHP local, elimina la cookie PHPSESSID y redirige al navegador al flujo de invalidación de Authentik (/if/flow/portal-ciudadano-logout-flow/). Authentik desautentica la cookie de SSO y retorna al usuario a index.php limpio. |
conexion.php |
Modificado | Parametrización dinámica por variables de entorno Docker (DB_HOST, DB_USER, etc.) y desactivación del modo estricto de excepciones de MySQLi (mysqli_report(MYSQLI_REPORT_OFF)) necesario para que el código PHP 7 legado ejecute en PHP 8.1 sin fallas fatales. |
portal.php |
Modificado | Protección y control de conexiones secundarias (bases no migradas como turnos y deportes) para evitar que conexiones fallidas interrumpan la carga del panel del vecino. |
index.php |
Modificado | Incorporación del botón oficial "Iniciar sesión con Authentik" integrado con la estética municipal. |
| 71 archivos PHP | Limpieza BOM | Remoción de la marca de orden de bytes UTF-8 (\xef\xbb\xbf) que provocaba que se emitiera salida previa a session_start(), bloqueando el envío de cookies de sesión. |
Estructura del Código Implementado
// 1. Extraer datos de UserInfo devueltos por Authentik
$cuit = $attributes['cuit'] ?? ($user_info['preferred_username'] ?? '');
$dni = $attributes['dni'] ?? '';
$mail = $user_info['email'] ?? '';
// 2. BÚSQUEDA JERÁRQUICA: Evitar duplicar registros en tabla usuarios
$usuario_encontrado = null;
// Criterio 1: Búsqueda por CUIT o Usuario
if (!empty($cuit)) {
$stmt = $conn->prepare("SELECT * FROM usuarios WHERE cuit = ? OR usuario = ? LIMIT 1");
$stmt->bind_param("ss", $cuit, $cuit);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows > 0) $usuario_encontrado = $res->fetch_assoc();
}
// Criterio 2: Fallback por DNI si no se encontró por CUIT
if (!$usuario_encontrado && !empty($dni)) {
$stmt = $conn->prepare("SELECT * FROM usuarios WHERE dni = ? LIMIT 1");
$stmt->bind_param("s", $dni);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows > 0) $usuario_encontrado = $res->fetch_assoc();
}
// 3. FUSIÓN O ALTA
$token_sesion = bin2hex(random_bytes(32));
if ($usuario_encontrado) {
// REUTILIZAR id_usuario HISTÓRICO: conserva sus inmuebles, autos y pagos
$stmt_up = $conn->prepare("UPDATE usuarios SET token = ?, activo = 1, fechaum = CURDATE() WHERE id_usuario = ?");
$stmt_up->bind_param("si", $token_sesion, $usuario_encontrado['id_usuario']);
$stmt_up->execute();
$_SESSION['username'] = $usuario_encontrado['usuario'];
$_SESSION['tokenmuni'] = $token_sesion;
} else {
// USUARIO NUEVO: dar de alta con atributos de Authentik
// ... INSERT INTO usuarios ...
}
header('Location: portal.php');
exit();
session_start();
// 1. Generar state criptográfico anti-CSRF y almacenar en sesión local
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;
// 2. Parámetros estándar OpenID Connect
$client_id = 'portal-ciudadano-legacy';
$redirect_uri = 'http://192.168.10.154:8081/authentik_callback.php';
$scope = 'openid profile email';
$auth_url = 'http://192.168.10.154:9000/application/o/authorize/?' . http_build_query([
'response_type' => 'code',
'client_id' => $client_id,
'redirect_uri' => $redirect_uri,
'scope' => $scope,
'state' => $state
]);
header('Location: ' . $auth_url);
exit();
session_start();
// 1. Destruir sesión PHP y expirar cookie local
$_SESSION = array();
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
session_unset();
session_destroy();
// 2. Redirigir al flujo de invalidación de Authentik para desautenticar la sesión SSO
$authentik_base_url = 'http://192.168.10.154:9000';
$logout_url = rtrim($authentik_base_url, '/') . '/if/flow/portal-ciudadano-logout-flow/';
header("Location: " . $logout_url);
exit();
6. Guía para Integrar Nuevos Sistemas Municipales a Authentik SSO
Protocolo estandarizado paso a paso para cualquier lenguaje (PHP, Node, Python, .NET)Cualquier nuevo desarrollo o sistema municipal existente puede sumarse a la plataforma de identidad única Authentik siguiendo estos 4 pasos estandarizados:
Dar de alta el Proveedor en Authentik
- Ingresar al Administrador de Authentik $\to$ Applications $\to$ Providers.
- Crear un OAuth2/OpenID Provider.
- Authorization flow: Elegir
implicit-consent(evita pantallas de confirmación redundantes). - Invalidation flow: Asociar el flujo de logout municipal (
portal-ciudadano-logout-flow). - Redirect URIs: Registrar las URLs de callback autorizadas y las URLs de post-logout.
Asignar Scopes y Atributos
- En Property Mappings del Provider, incluir:
openid,email,profile.Portal Ciudadano Attributes: Este mapping entrega directamente en el endpoint UserInfo el CUIT, DNI, domicilio y teléfono del vecino.
- Crear la Application en Authentik vinculando el Provider creado.
Implementar el Flujo OIDC en la Aplicación
- Ruta Login: Redirigir a
http://192.168.10.154:9000/application/o/authorize/conclient_id,redirect_uriystate. - Ruta Callback: Recibir el
codey pedir el token haciendo POST ahttp://192.168.10.154:9000/application/o/token/. - UserInfo: Con el token, consultar
http://192.168.10.154:9000/application/o/userinfo/para extraer la identidad del ciudadano.
Sincronizar el Cierre de Sesión (SLO)
- Al hacer logout en el sistema, destruir la sesión o JWT local.
- Redirigir al flujo de logout de Authentik:
http://192.168.10.154:9000/if/flow/portal-ciudadano-logout-flow/. - Authentik limpiará la sesión central y devolverá al usuario a la URL de inicio configurada.
Buena Práctica para Base de Datos Locales:
Nunca utilices el correo electrónico como clave primaria para vincular ciudadanos; utiliza siempre el CUIT (que viene en preferred_username o en attributes.cuit). El CUIT es único, inmutable y garantiza que ningún trámite se desvincule aunque el vecino cambie de email.
Portal Ciudadano Operativo
El sistema se encuentra 100% desplegado y validado en el servidor municipal listo para su uso institucional.