15 février 2026 · 6 min read

LTI DeepLinking

Offrez la possibilité de choisir vos exercices

#LTI #e-learning #standard #LMS

DeepLinking (DL)

Comme nous l’avons vu dans le post LTI dans les détails, intégrer un outil LTI nécessite une étape de registration c’est-à-dire un échange d’informations entre l’outil et le LMS pour établir un lien de confiance. Une fois cette relation établie, un administrateur configure l’outil et les enseignants peuvent l’ajouter dans leurs cours autant de fois qu’ils le souhaitent. Le problème apparaît quand l’outil tiers propose un catalogue d’exercices. Chaque exercice nécessite sa propre configuration, donc son propre passage par la registration. Pour dix exercices, dix enregistrements. C’est un frein réel à l’adoption. C’est ce que Deep Linking résout. Au lieu de multiplier les configurations, l’enseignant, lance l’outil directement depuis Moodle, navigue dans le catalogue proposé par l’outil, sélectionne l’exercice de son choix (ou plusieurs), et un lien direct vers cette ressource est automatiquement créé dans le cours.

Activer l’option deep linking dans le LMS

Lorsque un administrateur d’un LMS souhaite autorisé un outil à proposer un catalogue de ressources il doit le configurer au moment de la registration.

Par exemple avec Moodle :

Activation DeepLinking dans Moodle

Cela permet à l’enseignant de pouvoir choisir une ressource (exercice, video etc…). moodle présente un bouton Selectionner du contenu au moment d’intégrer l’outil dans un cours.

bouton selection de contenu dans Moodle

Le flux de lancement Deep Linking

Le lancement se déroule exactement de la même façon que le launch standard décrit dans le post LTI dans les détails avec pour seule différence le message_type du JWT qui vaut LtiDeepLinkingRequest au lieu de LtiResourceLinkRequest. C’est ce claim qui indique à l’outil qu’il ne doit pas afficher une ressource, mais proposer une interface de sélection.

Moodle initie la session exactement comme pour un launch classique, il crée un formulaire HTML autosoumis en POST vers l’endpoint de l’outil. L’enseignant est redirigé vers l’outil avec un JWT signé contenant le contexte du cours, son identité, ses rôles, et un claim supplémentaire deep_linking_settings qui décrit ce que Moodle accepte comme types de retour.

L’outil prend alors le contrôle. Il vérifie le JWT comme il le ferait pour un launch standard, identifie l’enseignant et son contexte, puis affiche son interface de sélection — un catalogue d’exercices, un explorateur de ressources, un formulaire de création. La spec laisse l’outil entièrement libre sur cette expérience. Moodle peut ouvrir ce flux dans une iframe ou une popup pour que l’interface du cours reste visible en arrière-plan, mais ce n’est pas une obligation.

Une fois la sélection faite, l’outil construit un JWT de réponse — le LtiDeepLinkingResponse — contenant la description de la ressource choisie, et le POST vers l’URL deep_link_return_url fournie par Moodle dans le claim deep_linking_settings. Moodle reçoit ce JWT, vérifie sa signature, et crée l’activité dans le cours.

Un détail important : l’outil doit toujours rediriger vers deep_link_return_url, même si l’enseignant n’a rien sélectionné. C’est ce qui permet à Moodle de fermer proprement l’iframe ou la popup ouverte au départ.

Le LtiDeepLinkingRequest

Au moment du lauch l’id token devient :

{
"nonce": "fd6383991c494f1db873aea6eac5f7184933707b33d911f1b1cd8cb87ec90090",
"iat": 1775714375,
"exp": 1775714435,
"iss": "http://localhost",
"aud": "v6NOc0mEFNce1wI",
"https://purl.imsglobal.org/spec/lti/claim/deployment_id": "2",
"https://purl.imsglobal.org/spec/lti/claim/target_link_uri": "http://localhost:8000/lti/launch/",
"sub": "2",
"https://purl.imsglobal.org/spec/lti/claim/lis": {
"person_sourcedid": "",
"course_section_sourcedid": ""
},
"https://purl.imsglobal.org/spec/lti/claim/roles": [
"http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator",
"http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor",
"http://purl.imsglobal.org/vocab/lis/v2/system/person#Administrator"
],
"https://purl.imsglobal.org/spec/lti/claim/context": {
"id": "2",
"label": "pyLTI",
"title": "PYTHON LTI",
"type": [
"CourseSection"
]
},
"https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiDeepLinkingRequest",
"https://purl.imsglobal.org/spec/lti/claim/launch_presentation": {
"locale": "fr"
},
"https://purl.imsglobal.org/spec/lti/claim/ext": {
"lms": "moodle-2"
},
"https://purl.imsglobal.org/spec/lti/claim/tool_platform": {
"product_family_code": "moodle",
"version": "2025100603.11",
"guid": "aa85caf65877b6e8f2e5cfd314c9805e",
"name": "local",
"description": "localhost"
},
"https://purl.imsglobal.org/spec/lti/claim/version": "1.3.0",
"https://purl.imsglobal.org/spec/lti/claim/custom": {
"niveau": "Terminale",
"debut_cours": "2026-04-03T23:00:00+00:00",
"fin_cours": "2027-04-03T23:00:00+00:00"
},
"https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings": {
"accept_types": [
"ltiResourceLink"
],
"accept_presentation_document_targets": [
"frame",
"iframe",
"window"
],
"accept_copy_advice": false,
"accept_multiple": true,
"accept_unsigned": false,
"auto_create": false,
"can_confirm": false,
"deep_link_return_url": "http://localhost/mod/lti/contentitem_return.php?course=2&id=2&sesskey=ifDNXFlCBh",
"title": "Django - LTI DL",
"text": ""
}
}

On remarque deux choses :

  • Le messageType devient "https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiDeepLinkingRequest" au lieu de "https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiResourceLinkRequest" pour un launch classique.
  • L’ajout du claim "https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings permet de spécifier les paramètres de l’outil de création de lien profond.
"https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings": {
"accept_types": [
"ltiResourceLink"
],
"accept_presentation_document_targets": [
"frame",
"iframe",
"window"
],
"accept_copy_advice": false,
"accept_multiple": true,
"accept_unsigned": false,
"auto_create": false,
"can_confirm": false,
"deep_link_return_url": "http://localhost/mod/lti/contentitem_return.php?course=2&id=2&sesskey=ifDNXFlCBh",
"title": "Django - LTI DL",
"text": ""
}
  • accept_types liste les types de ressources que Moodle peut recevoir. Ici ["ltiResourceLink"] — Moodle attend un lien vers une ressource LTI. C’est le type le plus courant et le seul que Moodle supporte dans cette configuration.

  • accept_presentation_document_targets indique dans quels contextes d’affichage Moodle pourra intégrer la ressource retournée — frame, iframe ou window. L’outil peut utiliser cette information pour n’exposer dans son catalogue que les ressources compatibles avec ces modes d’affichage.

  • accept_multiple à true signifie que l’outil peut retourner plusieurs ressources en une seule session. L’enseignant pourrait sélectionner trois exercices d’un coup et Moodle créerait trois activités dans le cours. Si ce champ est à false, l’outil doit limiter la sélection à un seul item.

  • auto_create à false est important. Quand il est à true, Moodle crée immédiatement l’activité dans le cours sans demander confirmation à l’enseignant. À false, Moodle présente d’abord un aperçu avant de créer le lien. Dans un environnement de production, laisser ce champ à false est plus sûr.

  • accept_unsigned à false signifie que Moodle exige que le JWT de réponse soit signé par l’outil avec sa clé privée. Ne jamais passer ce champ à true en production.

  • deep_link_return_url est l’URL vers laquelle l’outil doit poster sa réponse une fois la sélection terminée. L’outil doit conserver cette URL tout au long de son flux de sélection.

  • title et text sont des suggestions du LMS pour préremplir le titre et la description de la ressource dans l’interface de l’outil. L’outil peut les ignorer.

Le LMS affiche alors la page renvoyée par l’outil. Il s’agit d’une page HTML représentant un catalogue de ressource.

Moodle Select Content

Le LtiDeepLinkingResponse

Une fois l’enseignant a sélectionné sa ressource, l’outil construit un JWT signé avec sa clé privée et le poste vers la deep_link_return_url via un formulaire HTML auto-soumis.

<form
id="lti13_deep_link_auto_submit"
action="http://localhost/mod/lti/contentitem_return.php?course=2&id=2&sesskey=ifDNXFlCBh"
method="POST"
>
<input type="hidden" name="JWT" value="eyJ0eXAiOiJKV1Qi..." />
</form>
<script type="text/javascript">
document.getElementById("lti13_deep_link_auto_submit").submit();
</script>

L’action du formulaire est exactement la deep_link_return_url reçue dans le claim deep_linking_settings. Le JWT est posté dans un champ caché nommé JWT. Le script soumet le formulaire sans aucune interaction de l’enseignant, il est redirigé automatiquement vers Moodle qui reçoit la réponse.

Une fois décodé, le JWT contient :

{
"iss": "v6NOc0mEFNce1wI",
"aud": [
"http://localhost"
],
"exp": 1775762232,
"iat": 1775761632,
"nonce": "nonce-349d991133b044a896847b62f53d1f4f50c92e71344711f198a08cb87ec90090",
"https://purl.imsglobal.org/spec/lti/claim/deployment_id": "2",
"https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiDeepLinkingResponse",
"https://purl.imsglobal.org/spec/lti/claim/version": "1.3.0",
"https://purl.imsglobal.org/spec/lti-dl/claim/content_items": [
{
"type": "ltiResourceLink",
"title": "Variables et types",
"url": "http://localhost:8000/lti/launch/",
"custom": {
"exercice": "variables"
}
}
],
"https://purl.imsglobal.org/spec/lti-dl/claim/data": null
}

iss et aud sont inversés par rapport au request car c’est maintenant l’outil qui s’identifie comme émetteur et Moodle comme destinataire. Moodle vérifie la signature avec la clé publique de l’outil déclarée lors de la registration.

Partager