Skip to Content

Chapitre 13.5 — Construire un outil LTI 1.3 en Symfony

Partie 13 : Interopérabilité — Chapitre 5/5 Version de référence : Symfony 7.4 / LTI 1.3 Advantage.

⏱️ TL;DR

  • LTI (Learning Tools Interoperability) permet à un outil externe (votre app Symfony) de s’intégrer dans une plateforme LMS (Moodle) : l’utilisateur clique dans Moodle, et votre app s’ouvre avec le contexte (qui, quel cours, quel rôle) — sans re-login.
  • LTI 1.3 repose sur OIDC + JWT : la plateforme envoie un id_token (JWT signé) contenant les claims du lancement. L’outil vérifie la signature via le JWKS de la plateforme.
  • Enregistrement : échange de client_id, deployment_id, des URLs (auth, token, JWKS) et des clés entre plateforme et outil.
  • N’implémentez pas la crypto vous-même : utilisez une bibliothèque LTI 1.3 éprouvée.
  • Services Advantage : Deep Linking (choisir un contenu à insérer), AGS (renvoyer des notes au carnet Moodle), NRPS (récupérer la liste des inscrits).
  • C’est QuizLab de votre cours Moodle — construit ici en Symfony.

🎯 Objectifs

  • Comprendre le rôle « outil » et le flux de lancement LTI 1.3.
  • Mettre en place les endpoints (login OIDC, lancement, JWKS).
  • Valider le id_token en sécurité.
  • Connaître Deep Linking, AGS et NRPS.

1. Le principe : outil vs plateforme

  • La plateforme (Moodle) héberge les cours et lance des outils.
  • L’outil (votre app Symfony) fournit une fonctionnalité (un quiz, un exercice interactif, une visio…).

Quand un enseignant ajoute votre outil à un cours et qu’un étudiant clique dessus, Moodle lance votre app en lui transmettant, de façon sécurisée, le contexte : l’identité de l’utilisateur, ses rôles, le cours, le lien de ressource. L’étudiant n’a pas à créer un compte chez vous — l’identité vient de Moodle.

💡 Pour un dev / lecteur du cours Moodle : dans votre cours Moodle, QuizLab était l’outil LTI (côté Next.js/headless). Ici, on construit le même genre d’outil, mais en Symfony — qui devient le tool provider. C’est le pont direct entre les deux cours : Symfony comme brique d’un écosystème e-learning.

2. LTI 1.3 = OIDC + JWT

LTI 1.3 (« LTI Advantage ») s’appuie sur des standards éprouvés :

  • OIDC (OpenID Connect) pour l’initiation du lancement.
  • JWT signés (JWS) pour transporter les données de lancement, vérifiés par JWKS (les clés publiques de chaque partie).

3. Les données de lancement (claims)

Le id_token validé contient des claims LTI, notamment :

  • l’utilisateur : sub (identifiant), nom, email (si partagé) ;
  • les rôles : Instructor, Learner… ;
  • le contexte : le cours (id, titre) ;
  • le resource link : l’instance précise de l’activité ;
  • des custom claims (paramètres configurés côté Moodle) ;
  • les endpoints des services (AGS, NRPS) pour les appels retour.

À partir de là, votre app connaît qui fait quoi et dans quel cours — sans login.

4. Les endpoints côté Symfony

Un outil LTI 1.3 expose (au minimum) trois routes :

RouteRôle
/lti/login (OIDC init)reçoit l’initiation de lancement, redirige vers l’auth de la plateforme
/lti/launchreçoit le id_token, le valide, ouvre l’outil
/lti/jwksexpose les clés publiques de l’outil (pour que la plateforme vérifie vos JWT — Deep Linking, AGS)

On les implémente comme des contrôleurs Symfony classiques (Partie 4), en s’appuyant sur une bibliothèque LTI.

5. Utiliser une bibliothèque (jamais sa propre crypto)

La validation JWT/JWKS, les nonces, les services Advantage sont complexes et critiques en sécurité. On utilise une bibliothèque éprouvée — par exemple oat-sa/lib-lti1p3-core (une lib PHP LTI 1.3 complète), qu’on intègre dans Symfony.

// squelette (avec une lib LTI) : validation du lancement final class LtiLaunchController extends AbstractController { public function __construct(private readonly LtiToolService $lti) {} // wrap de la lib #[Route('/lti/launch', name: 'lti_launch', methods: ['POST'])] public function launch(Request $request): Response { // la lib : vérifie signature (JWKS plateforme), nonce, aud=client_id, expiration $launch = $this->lti->validateLaunch($request); $userId = $launch->getUserIdentity()->getIdentifier(); $roles = $launch->getRoles(); $context = $launch->getContext(); // le cours // ... ouvrir l'outil pour cet utilisateur/rôle/cours return $this->render('lti/tool.html.twig', [ /* ... */ ]); } }

⚠️ Piège sécurité (crypto maison) : n’écrivez jamais votre propre validation JWT/JWKS pour LTI. Une erreur (ne pas vérifier la signature, accepter un alg: none, ignorer le nonce/aud/expiration) ouvre une usurpation d’identité (un attaquant se fait passer pour un enseignant). Utilisez une bibliothèque maintenue qui gère la validation complète, le rejeu (nonce), et les rotations de clés (JWKS). La sécurité LTI est dans ces détails.

6. Les services LTI Advantage

Une fois le lancement validé, l’outil peut dialoguer avec la plateforme (appels retour authentifiés par OAuth2 client-credentials + JWT) :

  • Deep Linking : l’enseignant configure l’activité ; votre outil lui propose un choix de contenus (ex. « quel quiz insérer ? ») et renvoie à Moodle les content items sélectionnés.
  • AGS (Assignment and Grade Services) : votre outil renvoie des notes au carnet de notes Moodle (créer une colonne, poster un score). C’est ce qui rend un quiz externe noté dans Moodle.
  • NRPS (Names and Role Provisioning Services) : récupérer la liste des inscrits du cours (pour, par ex., préparer des groupes).

Avec AGS + NRPS, votre outil Symfony devient un vrai composant pédagogique : lancé depuis Moodle, il note dans Moodle et connaît la classe. C’est exactement le capstone QuizLab de votre cours Moodle, réalisé côté Symfony.

7. Récapitulatif : Symfony dans l’écosystème EdTech

Vous savez désormais les deux sens :

  • Symfony pilote Moodle de l’extérieur (Web Services, chapitre 13.4).
  • Symfony est lancé par Moodle comme outil LTI (ce chapitre), avec notes retour.

Ajouté à WordPress headless (13.3) et à vos cours Moodle/WordPress, vous couvrez une niche complète : construire, intégrer et connecter des plateformes de contenu et d’apprentissage. Peu de profils font ça — d’où la valeur (Partie 17).

✏️ Exercices

Exercice 1. Décrivez les 4 étapes du lancement LTI 1.3, du clic de l’étudiant à l’affichage de l’outil.

✅ Solution

  1. L’étudiant clique dans Moodle → Moodle envoie une initiation OIDC à /lti/login de l’outil. 2. L’outil redirige vers l’endpoint d’auth de la plateforme (avec state et nonce). 3. Moodle POST le id_token (JWT signé, contenant les claims) à /lti/launch. 4. L’outil valide le JWT (signature via JWKS de la plateforme, nonce, aud=client_id, expiration), extrait les claims (utilisateur, rôles, contexte) et affiche l’outil. L’étudiant n’a pas eu à se connecter chez l’outil.

Exercice 2. Pourquoi ne jamais implémenter soi-même la validation du id_token LTI ?

✅ Solution

Parce que la validation est critique et pleine de pièges : oublier de vérifier la signature, accepter alg: none, ne pas contrôler le nonce (rejeu), l’aud, l’expiration, ou mal gérer la rotation des clés (JWKS)usurpation d’identité (se faire passer pour un enseignant, poster de fausses notes). Une bibliothèque LTI 1.3 maintenue gère tout ça correctement. La sécurité LTI réside précisément dans ces détails cryptographiques.

Exercice 3. Quel service LTI Advantage permet à votre outil Symfony de renvoyer une note dans Moodle, et pourquoi est-ce important ?

✅ Solution

AGS (Assignment and Grade Services) : l’outil peut créer une colonne et poster un score dans le carnet de notes Moodle (via un appel authentifié). C’est important car cela rend une activité externe (un quiz dans votre app Symfony) notée dans Moodle comme une activité native — l’enseignant retrouve la note au bon endroit, sans ressaisie. C’est ce qui fait d’un outil LTI un vrai composant pédagogique intégré (capstone QuizLab).

🧠 Quiz de révision

1. Quel rôle joue Symfony dans une intégration LTI ?

Celui d’outil (tool provider) lancé par une plateforme LMS (Moodle) avec le contexte de l’utilisateur/cours/rôle.

2. Sur quels standards repose LTI 1.3 ?

OIDC (initiation) + JWT signés (données de lancement), vérifiés via JWKS.

3. Quels endpoints un outil LTI expose-t-il ?

/lti/login (init OIDC), /lti/launch (validation du id_token), /lti/jwks (clés publiques de l’outil).

4. Faut-il coder sa propre validation JWT LTI ?

Non : on utilise une bibliothèque LTI 1.3 éprouvée (validation signature/nonce/aud/expiration/JWKS). Le faire soi-même = risque d’usurpation.

5. Que permettent AGS et NRPS ?

AGS : renvoyer des notes au carnet Moodle. NRPS : récupérer la liste des inscrits du cours.


Fin de la Partie 13. BookLab (et vous) savez désormais dialoguer avec le monde : consommer des API (HttpClient), gérer des webhooks, ponter WordPress et Moodle, et être un outil LTI. Vous reliez vos trois univers — une compétence rare.

Prochaine étape : Partie 14 — Tests & qualité — garantir que tout ça fonctionne et le reste.