La arquitectura LTI no empieza cuando Moodle, Canvas u otro LMS envía un id_token. Empieza antes: cuando decides qué responsabilidades conserva la plataforma educativa y cuáles pertenecen a la herramienta externa. Esa decisión apenas se ve en una demostración, pero determina si estás construyendo un producto realmente desacoplado o un plugin distribuido que continúa dependiendo del LMS para casi todo.
Hacer funcionar un launch es la parte visible y, normalmente, la más sencilla. La complejidad aparece después, cuando hay que resolver identidad, tenants, roles, permisos, cursos copiados, selección de contenidos, roster, calificaciones, privacidad, rotación de claves y soporte para varias plataformas. Si esas decisiones se improvisan dentro de cada endpoint, la integración puede funcionar hoy y convertirse mañana en una fuente constante de deuda técnica.
Por eso conviene tratar LTI 1.3 como una frontera de producto y no solo como un mecanismo de acceso. En este artículo veremos cómo diseñar esa frontera, qué información debería cruzarla, cómo separar el protocolo del dominio y cuándo una arquitectura LTI aporta más valor que un plugin tradicional. El objetivo no es explicar únicamente cómo validar un token, sino cómo construir una integración que pueda mantenerse, observarse y evolucionar sin arrastrar las estructuras internas del LMS.
TL;DR
La arquitectura LTI no consiste solo en abrir una herramienta desde el LMS. Define una frontera de producto: establece qué sistema controla la identidad, el contexto, los datos, la seguridad y cada responsabilidad operativa.
- LTI no debería entenderse únicamente como “abrir una URL desde Moodle”.
- Una buena arquitectura LTI separa el contexto académico del dominio propio de la herramienta.
- El launch es solo la puerta de entrada: detrás aparecen identidad, tenancy, autorización, datos, roster, contenido y calificaciones.
- LTI 1.3 utiliza OpenID Connect, JWT, claves asimétricas y servicios OAuth 2.0; implementarlo bien exige algo más que validar una firma.
- El LMS puede conservar cursos, matrículas, roles académicos y libro de calificaciones sin convertirse en el backend del producto externo.
- La pregunta decisiva sigue siendo: qué responsabilidad pertenece al LMS y cuál pertenece al producto.
Una integración madura comparte contratos. No comparte las tripas de los sistemas.

Desde fuera parece un enlace
El alumno entra en Moodle, pulsa una actividad y se abre una herramienta. Desde la interfaz, LTI puede parecer exactamente eso: un enlace con autenticación. Sin embargo, una arquitectura LTI empieza mucho antes de ese clic y continúa después del launch.
Pero debajo hay una pregunta arquitectónica bastante más importante:
¿Dónde termina el LMS y dónde empieza tu producto?
La respuesta condiciona el modelo de datos, la seguridad, el roadmap, el despliegue y hasta la forma de atender incidencias. Si no defines esa frontera, puedes terminar construyendo una aplicación externa que sigue dependiendo de Moodle para casi todo: usuarios, permisos, tablas, configuración y lógica de negocio. Para ver el contraste en un caso concreto, puedes consultar esta guía práctica de integración LTI con Moodle.
Entonces no has creado un producto desacoplado. Has movido una pantalla fuera del LMS.
Si respondes bien, en cambio, LTI se convierte en un contrato estable entre dos sistemas que conocen cosas distintas y evolucionan a ritmos distintos.
La visión mínima: LTI como launch
La implementación más básica suele imaginar este flujo:
LMS
↓
launch
↓
ToolFunciona y, para algunos casos, puede ser suficiente. El problema aparece cuando la herramienta empieza a necesitar algo más que saber quién ha pulsado el enlace:
- identificar la institución que está entrando;
- conocer el curso y el recurso concreto;
- interpretar roles académicos;
- seleccionar o crear contenido;
- consultar participantes;
- devolver calificaciones;
- conservar configuración por placement;
- soportar más de un LMS;
- operar con distintas políticas de privacidad;
- diagnosticar por qué falla un launch en un cliente y no en otro.
En ese momento, LTI deja de ser una pieza de SSO. A partir de ahí, la arquitectura LTI empieza a formar parte del diseño del producto.

Cómo funciona un launch en una arquitectura LTI
LTI 1.3 no envía simplemente un formulario con un usuario y un curso. El flujo se apoya en OpenID Connect y en mensajes firmados. De forma simplificada:
- El LMS inicia el login contra el endpoint de la herramienta.
- La herramienta genera y conserva
stateynonce, y redirige al endpoint de autorización de la plataforma. - El LMS autentica al usuario y devuelve un
id_tokenmediante un POST alredirect_uriregistrado. - La herramienta valida la firma utilizando la JWKS de la plataforma.
- También valida emisor, audiencia, tiempos,
nonce, deployment y tipo de mensaje. - Solo después crea una sesión local o ejecuta el caso de uso correspondiente.
La especificación LTI 1.3 Core de 1EdTech define los mensajes y claims principales. En una implementación real conviene prestar atención, como mínimo, a:
iss, que identifica a la plataforma emisora;audyazp, que delimitan el cliente destinatario;sub, que identifica al usuario dentro del contexto del emisor;exp,iatynonce, que ayudan a impedir reutilizaciones y mensajes fuera de ventana;deployment_id, que identifica la instalación concreta de la herramienta;message_type, que diferencia un resource link launch de un Deep Linking request;context,resource_linkyroles, que transportan contexto académico;- los claims de servicios, que anuncian endpoints y scopes disponibles para NRPS o AGS.
Un error habitual consiste en validar la firma y considerar que el trabajo ha terminado. La firma responde a “quién emitió este token y si fue alterado”. En cambio, no responde por sí sola a “si estaba destinado a esta instalación, si sigue vigente, si el nonce ya fue usado o si el deployment está activo”.
Registro, deployment y tenant no son lo mismo
Este punto es especialmente importante en productos SaaS.
En LTI 1.1 era frecuente asociar una integración a una consumer key y un secreto compartido. LTI 1.3 separa mejor el registro técnico de la herramienta y sus deployments. La propia guía de migración de 1EdTech propone identificar una integración mediante la combinación de issuer, client_id y deployment_id.
Por tanto, esa separación tiene consecuencias directas sobre el modelo multitenant de una arquitectura LTI:
Platform registration
└── issuer + client_id
├── deployment A → institución A
├── deployment B → institución B
└── deployment C → institución CNo asumiría que client_id equivale siempre a un cliente de negocio. Tampoco usaría el dominio del LMS, el correo del usuario o el context_id para resolver el tenant. La frontera debería contar con un registro explícito de integraciones:
LtiRegistration
- issuer
- client_id
- auth_login_url
- auth_token_url
- jwks_url
- status
LtiDeployment
- registration_id
- deployment_id
- tenant_id
- enabled_services
- privacy_policy
- statusEsto permite desactivar un deployment sin romper los demás, aplicar políticas por institución y conservar una trazabilidad clara. También prepara el producto para registro dinámico cuando la plataforma lo soporte. La especificación de Dynamic Registration automatiza parte del intercambio de configuración, pero no elimina la necesidad de gobernar qué institución, contrato y tenant representa cada deployment.
El LMS conoce el contexto. Tu producto conoce su dominio
Esta separación es una de las ideas más útiles de una buena arquitectura LTI.
| El LMS puede ser owner de | La herramienta puede ser owner de |
|---|---|
| Matrículas y pertenencia al curso | Actividad especializada |
| Contexto académico | Datos de dominio |
| Roles institucionales | Reglas de negocio propias |
| Navegación general | Experiencia de usuario |
| Libro de calificaciones | Cálculo del resultado |
| Disponibilidad del recurso en el curso | Configuración funcional |
| Políticas institucionales | Roadmap y ciclo de despliegue |
La frontera no implica que cada dato viva en un solo sitio sin ninguna copia. Implica que existe un system of record claro y que las réplicas tienen una finalidad, una caducidad y una estrategia de reconciliación. Esta separación también es la base de una arquitectura Headless LMS que pueda evolucionar sin vaciar al LMS de su responsabilidad académica.
Por ejemplo, la herramienta puede necesitar conservar el nombre de un curso para mostrarlo en su panel. Eso no convierte su base de datos en la fuente oficial del catálogo académico. Del mismo modo, el LMS puede mostrar una calificación calculada por la herramienta sin apropiarse de la lógica que la produjo.

LTI Advantage: servicios, no magia
LTI 1.3 moderniza la relación de confianza. Además, LTI Advantage añade contratos para resolver necesidades habituales sin depender de una API propietaria de Moodle, Canvas o cualquier otra plataforma compatible. Dentro de una arquitectura LTI, estos servicios conectan capacidades sin mezclar los dominios de ambos sistemas.
Deep Linking: seleccionar antes de lanzar
Deep Linking 2.0 permite que el docente entre en la herramienta, seleccione o cree un recurso y lo devuelva al LMS como un elemento enlazado. No es únicamente un selector bonito: permite que la herramienta participe en la autoría y configuración sin obligar al LMS a conocer su catálogo interno.
El producto debería decidir qué configuración queda embebida en el enlace, cuál se guarda en su dominio y cómo versionar recursos que ya están utilizados en varios cursos.
NRPS: roster bajo demanda
Names and Role Provisioning Services permite consultar miembros y roles del contexto cuando la plataforma lo autoriza. Es útil para paneles docentes, actividades de grupo o procesos que necesitan conocer participantes antes de que todos hayan hecho launch.
Ahora bien, NRPS no obliga a replicar todo el roster en cada acceso. Conviene decidir si necesitas una consulta puntual, una caché temporal o una sincronización persistente. Cada opción cambia los requisitos de privacidad, borrado y consistencia.
AGS: resultados y line items
Assignment and Grade Services permite gestionar line items, publicar puntuaciones y consultar resultados. Es más expresivo que el antiguo Basic Outcomes y rompe la idea de que cada resource link solo puede asociarse a una columna simple.
En producto, la decisión importante no es solo “podemos enviar una nota”, sino:
- quién calcula el resultado;
- cuándo se considera definitivo;
- si el envío es síncrono o mediante una cola;
- cómo se reintenta sin duplicar efectos;
- qué ocurre si el LMS rechaza la puntuación;
- cómo se concilian cambios manuales en el libro de calificaciones.

No uses el email como identidad
Otro error común consiste en convertir el email recibido en el identificador principal del usuario. Es tentador porque resulta legible y parece estable. En la práctica puede cambiar, no estar disponible o no ser único entre instituciones.
En una arquitectura LTI, la identidad externa debería tratarse como una asociación contextual. Un modelo razonable puede conservar:
ExternalIdentity
- issuer
- client_id
- subject
- tenant_id
- local_user_id
- last_seen_atEl sub debe interpretarse dentro del emisor y del cliente correspondiente, no como un identificador universal. Nombre, email y avatar son atributos de perfil; no deberían ser la clave con la que relacionas progreso, permisos o facturación.
Además, este diseño ayuda a aplicar minimización de datos. Algunas herramientas necesitan nombre y correo. Otras pueden funcionar con un identificador opaco, rol y contexto. Cuantos más datos replicas, más superficie de sincronización, retención, privacidad y borrado introduces.
La integración debería transportar y conservar lo necesario, no todo lo disponible.
Los roles LTI no sustituyen tu autorización
Que el token incluya un rol de Instructor no significa que el usuario pueda ejecutar cualquier acción administrativa dentro de tu producto.
Los roles LTI describen la relación académica que comunica la plataforma. Tu herramienta sigue necesitando una política de autorización propia. Puede mapear roles externos a capacidades internas, pero ese mapeo debería ser explícito, configurable y verificable.
Por ejemplo:
Instructor → ver panel del contexto, configurar actividad
Learner → realizar actividad, consultar su resultado
Admin → no se concede automáticamente por un rol genéricoEste matiz evita que una diferencia de roles entre Moodle y Canvas termine abriendo permisos inesperados. También permite introducir capacidades específicas del producto que no tienen equivalente académico.
Un producto LTI debería sobrevivir a otro LMS
Una prueba conceptual muy útil es preguntarse:
Si mañana el cliente cambia Moodle por Canvas, ¿qué parte de tu producto desaparece?
Si la respuesta es “casi toda”, quizá la frontera no está bien diseñada.
Una herramienta puede tener adaptadores específicos para peculiaridades de cada plataforma. Aun así, una arquitectura LTI sostenible no debería introducir esas diferencias dentro de su dominio:
$DB->get_record('course', ...);El modelo deseable se parece más a este:
Moodle ──┐
Canvas ──┼── Adaptador LTI ──► Casos de uso ──► Dominio
Otro LMS ┘El adaptador valida el protocolo y traduce claims externos a comandos internos. La aplicación decide el caso de uso. El dominio trabaja con conceptos propios y no con URLs de claims, nombres de tablas de Moodle o particularidades del libro de calificaciones de Canvas.

Una arquitectura LTI que pueda mantenerse
Separaría al menos cinco capas o responsabilidades:
1. Registro de plataformas y deployments
Resuelve issuer, cliente, endpoints, JWKS, tenant, servicios habilitados y estado de la integración. No debería estar repartido entre variables de entorno y condicionales por cliente.
2. Adaptador de protocolo
Implementa login initiation, validación del launch, Deep Linking y obtención de tokens OAuth 2.0. Aquí viven state, nonce, JWT, JWKS, scopes y traducción de errores del protocolo.
3. Capa de aplicación
Convierte un launch válido en una intención: abrir una actividad, configurar un recurso, consultar un panel docente o continuar un intento.
4. Dominio del producto
Contiene actividad, progreso, evaluación, reglas y datos propios. No debería necesitar saber qué LMS originó la petición salvo que exista una regla de negocio real que lo justifique.
5. Adaptadores de salida
Encapsulan NRPS, AGS, webhooks internos, colas y observabilidad. Enviar una calificación no debería contaminar el modelo de dominio con detalles de OAuth o endpoints del LMS.
Como resultado, esta estructura actúa como una capa anticorrupción: el protocolo cambia en el borde; el producto conserva un lenguaje interno estable. Si quieres ampliar la perspectiva más allá del lanzamiento, en esta guía explico cómo encaja LTI dentro de la interoperabilidad educativa de un campus digital.
Seguridad: validar más que la firma
La Security Framework de 1EdTech define el uso de OpenID Connect, JWT, claves y OAuth 2.0 que acompaña a LTI 1.3. En una implementación de producción revisaría al menos:
statede un solo uso y vinculado al navegador que inició el flujo;noncepersistido temporalmente y rechazado si se reutiliza;- comprobación estricta de
iss,aud,azp,expeiat; - algoritmo permitido explícitamente, normalmente RS256 en LTI 1.3;
- selección de clave mediante
kidy actualización controlada de JWKS; - validación de
deployment_idcontra un deployment activo; - allowlist de redirect y target link URIs;
- separación entre sesión del producto y token recibido;
- almacenamiento seguro de claves privadas;
- rotación de claves publicando más de una clave durante la transición;
- tokens OAuth de corta duración y limitados a los scopes necesarios;
- logs sin tokens completos ni PII innecesaria.
Por último, trataría los iframes como una decisión de experiencia y seguridad, no como el comportamiento por defecto. Cookies SameSite, políticas CSP, navegadores restrictivos y bloqueos de terceros pueden hacer que una integración funcione en una pestaña y falle embebida.
La operación empieza después del launch
Un launch válido no garantiza que el producto sea operable. Las incidencias reales suelen requerir responder preguntas como:
- ¿qué issuer y deployment originaron la petición?;
- ¿qué
kidse utilizó y cuándo se refrescó la JWKS?; - ¿falló la autenticación o la autorización interna?;
- ¿el LMS ofreció el scope de AGS esperado?;
- ¿una calificación está pendiente, enviada, rechazada o reintentándose?;
- ¿el fallo afecta a una institución, a un curso o a todos los tenants?;
Por eso conviene asignar un correlation ID desde el login initiation y conservarlo durante launch, sesión, llamadas a servicios y jobs asíncronos. Además, las métricas deberían separar errores de protocolo, configuración, dependencia externa y dominio.
Para AGS utilizaría una cola con reintentos acotados, backoff y una clave de idempotencia funcional. El alumno no debería esperar a que el LMS confirme una calificación para ver completada su actividad. Primero se confirma el resultado en el producto; después se sincroniza y se hace visible su estado operativo.
Errores que convierten LTI en deuda técnica
Hay varios patrones que parecen acelerar la primera demo y encarecen todo lo que viene después:
Tratar el launch como un login genérico
Se pierde el resource link, el deployment, el contexto y la intención del mensaje. El usuario entra, pero el producto no sabe realmente a qué viene.
Crear usuarios y cursos sin una política de ciclo de vida
Cada launch duplica datos, pero nadie define actualización, retención, anonimización o borrado.
Usar email o context_id como tenant
Funciona en la primera instalación y colisiona cuando aparecen varios deployments, dominios o cursos regenerados.
Mezclar protocolo y dominio
Los casos de uso terminan recibiendo claims completos y comparando URIs de roles. Cualquier diferencia de plataforma se propaga por todo el código.
Enviar calificaciones dentro de la petición del alumno
La latencia y disponibilidad del LMS pasan a controlar la experiencia principal del producto.
No planificar rotación de claves
Todo funciona hasta que cambia un kid, caduca una clave o una plataforma mantiene temporalmente dos claves válidas.
Prometer “compatible con LTI 1.3” sin definir servicios
Core launch, Deep Linking, NRPS y AGS son capacidades distintas. La compatibilidad debería expresarse como una matriz verificable por plataforma y deployment.
Arquitectura LTI o plugin: una decisión contextual
No todo debería salir del LMS. Un plugin sigue siendo una opción excelente cuando la funcionalidad depende profundamente de APIs internas, es pequeña, solo existe para una instalación o puede compartir el ciclo de actualización de la plataforma. Tampoco conviene confundir LTI con una API de automatización: la API REST de Moodle resuelve otros contratos y puede coexistir con LTI.
| Pregunta | Favorece plugin | Favorece producto LTI |
|---|---|---|
| ¿Debe funcionar en varios LMS? | No | Sí |
| ¿Tiene dominio y datos propios? | Poco | Mucho |
| ¿Necesita desplegarse con frecuencia? | No | Sí |
| ¿Depende de eventos o tablas internas del LMS? | Mucho | Poco |
| ¿Requiere escalado independiente? | No | Sí |
| ¿Tiene roadmap comercial propio? | No | Sí |
| ¿La experiencia debe vivir dentro del LMS? | Completamente | Solo como punto de entrada |
La arquitectura LTI tiene sentido cuando existe una capacidad que merece una frontera propia. Si no existe esa independencia, externalizarla puede añadir autenticación, tenancy, observabilidad y operación sin obtener un beneficio real.
Cómo diseñar la frontera de una arquitectura LTI
Antes de escribir endpoints OIDC, documentaría estas decisiones:
Identidad
- ¿Qué clave relaciona la identidad externa con el usuario local?
- ¿Necesitamos nombre y email o basta un identificador opaco?
- ¿Cómo se fusionan o separan identidades de varias plataformas?
Tenant y deployment
- ¿Qué entidad de negocio representa cada deployment?
- ¿Puede un tenant tener varios deployments?
- ¿Cómo se desactiva una integración sin borrar su histórico?
Contexto y recurso
- ¿Qué significa un curso dentro del producto?
- ¿Qué configuración pertenece al resource link?
- ¿Qué ocurre cuando un curso se copia o se restaura?
Roles y autorización
- ¿Qué roles externos reconocemos?
- ¿Qué capacidades internas concede cada uno?
- ¿Qué acciones requieren permisos propios del producto?
Datos y privacidad
- ¿Cuál es el system of record de cada dato?
- ¿Qué información se replica y durante cuánto tiempo?
- ¿Cómo se atienden borrado, retención y auditoría?
Calificaciones y roster
- ¿La herramienta calcula y el LMS muestra?
- ¿La sincronización es inmediata o asíncrona?
- ¿Necesitamos roster completo, parcial o bajo demanda?
Operación
- ¿Qué observamos por issuer, deployment y contexto?
- ¿Cómo rotamos claves?
- ¿Qué podemos reintentar y qué necesita intervención humana?

Un camino de implementación razonable
No intentaría construir todo LTI Advantage en la primera iteración. En su lugar, construiría la arquitectura LTI por capas:
- Core launch seguro: registro, deployment, validación completa, sesión y observabilidad.
- Modelo de dominio desacoplado: identidad externa, contexto y resource link traducidos a conceptos internos.
- Deep Linking: cuando el docente necesite seleccionar o configurar contenido desde el LMS.
- AGS: con colas, idempotencia, estados y reconciliación.
- NRPS: solo si el caso de uso necesita roster antes del launch individual.
- Multi-LMS real: pruebas de contrato y adaptadores para diferencias documentadas.
- Registro dinámico y certificación: cuando el volumen de instalaciones justifique automatizar onboarding y demostrar conformidad.
Este orden reduce el riesgo de construir servicios que el producto todavía no necesita y obliga a resolver primero la frontera que sostiene todo lo demás.
Veredicto
LTI no es un plugin. Tampoco es simplemente una URL con SSO. Es una decisión de arquitectura LTI que debe sostenerse cuando cambian el LMS, el volumen o las necesidades del producto.
Es un contrato entre una plataforma que posee contexto educativo y una herramienta que posee una capacidad especializada. Ese contrato incluye identidad, seguridad, deployments, servicios, ownership de datos y responsabilidades operativas.
Cuando diseñas bien esa frontera consigues menos acoplamiento, más portabilidad, mejor ownership, un roadmap independiente y soporte multi-LMS más realista. Cuando la diseñas mal, solo trasladas fuera del LMS una dependencia que sigue siendo estructural.
En definitiva, ahí está el verdadero valor de LTI: no en abrir una pantalla, sino en permitir que dos productos colaboren sin dejar de ser productos distintos.
Conclusión: diseña la frontera antes de escribir código
Si tienes una integración LTI, dibuja dos columnas: LMS y Tool. Coloca usuarios, roles, cursos, datos, actividad, configuración, evaluación, claves, tenancy, observabilidad y reporting.
Después marca tres cosas para cada elemento:
- quién es el owner;
- qué información cruza la frontera;
- qué ocurre cuando la sincronización falla.
Las responsabilidades sobre las que dudes son probablemente las que más merece la pena aclarar antes de seguir desarrollando. Si necesitas convertir esas decisiones en una hoja de ruta, puedes revisar mi servicio de consultoría de arquitectura para plataformas educativas.


Deja una respuesta