Skip to Content

Chapitre 10.2 — Deep Linking

⏱️ TL;DRDeep Linking répond à une question simple : quel contenu de ton outil l’enseignant veut-il placer dans son cours ? Au lieu de coller une URL en dur, la plateforme lance ton outil dans un mode spécial — un id_token dont le claim .../lti/claim/message_type vaut LtiDeepLinkingRequest — accompagné d’un claim deep_linking_settings (qui contient notamment deep_link_return_url et accept_types). Ton outil affiche son catalogue, l’enseignant choisit, et ton outil renvoie un LtiDeepLinkingResponse : un JWT signé dont le claim .../lti-dl/claim/content_items porte le tableau des items choisis (ltiResourceLink, link, file, html, image). Ce JWT est POSTé au deep_link_return_url ; la plateforme crée alors la ou les activités dans le cours. Pas de jeton d’accès ici : tout passe par le lancement et une réponse signée.

🎯 Objectifs

  • Reconnaître un lancement LtiDeepLinkingRequest et lire deep_linking_settings.
  • Construire un LtiDeepLinkingResponse (JWT signé) avec des content_items.
  • Distinguer les types d’items (ltiResourceLink, link, file, html, image).
  • Comprendre où POSTer la réponse (deep_link_return_url) et ce que la plateforme en fait.

Le scénario : l’enseignant configure l’activité

En Partie 9, l’enseignant branchait ton outil, puis une activité pointait vers une URL de lancement fixe. Problème : ton catalogue a 200 exercices. Comment l’enseignant dit-il « je veux celui-là, sur les fractions, niveau 6e » ? À la main, en copiant une URL ? Fragile et pénible.

Deep Linking renverse la logique : c’est ton outil qui présente le choix. Quand l’enseignant clique sur « Ajouter du contenu depuis FormaCampus », la plateforme lance ton outil en mode sélection. Tu affiches ton catalogue, il choisit, tu renvoies le choix structuré. La plateforme crée l’activité — avec, déjà, le bon exercice et ses paramètres.

Temps 1 — Le lancement LtiDeepLinkingRequest

C’est un lancement LTI 1.3 normal (tout le flux OIDC + JWT de la Partie 9 s’applique : validation state, signature, iss, aud, exp, nonce), avec deux différences dans les claims :

{ "https://purl.imsglobal.org/spec/lti/claim/message_type": "LtiDeepLinkingRequest", "https://purl.imsglobal.org/spec/lti/claim/deep_linking_settings": { "deep_link_return_url": "https://moodle.ecole.fr/mod/lti/contentitem_return.php?course=9271&id=42", "accept_types": ["ltiResourceLink", "link"], "accept_presentation_document_targets": ["iframe", "window"], "accept_multiple": true, "auto_create": false, "title": "Choisir un exercice FormaCampus", "data": "opaque-token-a-renvoyer-tel-quel" } }
  • message_type vaut LtiDeepLinkingRequest (au lieu de LtiResourceLinkRequest) : c’est ce qui te dit « affiche un sélecteur, pas du contenu ».
  • Le claim deep_linking_settings porte les règles du jeu :
    • deep_link_return_url : l’URL où tu devras POSTer ta réponse. C’est la donnée capitale.
    • accept_types : les types d’items que la plateforme accepte (ici ltiResourceLink et link). N’en renvoie pas d’autres.
    • accept_multiple : l’enseignant peut-il choisir plusieurs items d’un coup ?
    • data : un jeton opaque que tu dois ré-émettre tel quel dans ta réponse (la plateforme s’en sert pour retrouver son contexte — comme un state).

💡 Réflexe — Lis accept_types avant d’afficher ton catalogue et filtre ce que tu proposes. Si la plateforme n’accepte que ltiResourceLink, n’affiche pas de bouton « insérer une image ». Renvoyer un type non listé = réponse rejetée. Et mémorise deep_link_return_url et data : tu en auras besoin au temps 3.

Temps 2 — L’enseignant choisit

Rien de normé ici : c’est ton interface. Tu affiches ton catalogue (recherche, filtres par niveau/chapitre), l’enseignant sélectionne un ou plusieurs exercices. Tu prépares alors, pour chaque choix, un content item.

Temps 3 — La réponse LtiDeepLinkingResponse

Ta réponse est un JWT que TON outil signe (avec sa clé privée — comme le client_assertion du chapitre 10.1). Ici, l’émetteur, c’est toi : iss = ton client_id, aud = l’iss de la plateforme. Le payload :

{ "iss": "formacampus-studio-client-id", "aud": "https://moodle.ecole.fr", "iat": 1893455940, "exp": 1893456240, "nonce": "nc-9f2a", "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/claim/deployment_id": "dep-1", "https://purl.imsglobal.org/spec/lti-dl/claim/data": "opaque-token-a-renvoyer-tel-quel", "https://purl.imsglobal.org/spec/lti-dl/claim/content_items": [ { "type": "ltiResourceLink", "title": "Entrainement calcul mental - fractions", "text": "20 questions, correction immediate", "url": "https://studio.formacampus.fr/lti/launch", "custom": { "chapitre": "fractions", "niveau": "6e", "exerciceId": "ex-4815" }, "lineItem": { "scoreMaximum": 20, "label": "Calcul mental - fractions", "resourceId": "ex-4815" } } ] }

Décryptage :

  • message_type = LtiDeepLinkingResponse : la plateforme sait que c’est un retour de sélection.
  • Le claim .../lti-dl/claim/data re-émet exactement le data reçu au temps 1.
  • Le claim .../lti-dl/claim/content_items est le cœur : un tableau d’items choisis.

Ce JWT, tu le POST au deep_link_return_url, généralement via un formulaire auto-soumis dans le navigateur (comme le lancement, mais dans l’autre sens) :

POST /mod/lti/contentitem_return.php?course=9271&id=42 HTTP/1.1 Host: moodle.ecole.fr Content-Type: application/x-www-form-urlencoded JWT=eyJhbGciOiJSUzI1NiIsImtpZCI6InN0dWRpby0yMDI2In0.eyJpc3M...

La plateforme vérifie ta signature (via ton jwks_uri), lit les content_items et crée l’activité dans le cours. Fin du parcours : l’exercice choisi est posé dans le cours, avec ses custom et, ici, sa colonne de note déjà prête.

Les types de content_items

Le champ type de chaque item dit à la plateforme quoi créer. Les cinq types :

typeCe que ça créeChamps clés
ltiResourceLinkUne activité lançable de ton outil (relance LTI ultérieure).url, title, custom, lineItem
linkUn lien externe simple (pas un relancement LTI).url, title, text
fileUn fichier à télécharger.url, title, mediaType
htmlUn fragment HTML inséré directement.html
imageUne image affichée.url, width, height

Le type roi est ltiResourceLink : c’est celui qui crée une activité relançable (à chaque clic, un vrai lancement LTI Core vers ton url), et qui peut embarquer une colonne de note via son sous-objet lineItem.

💡 Réflexe — Utilise le sous-objet lineItem d’un ltiResourceLink pour créer la colonne de carnet en même temps que l’activité. La plateforme crée l’exercice et sa colonne (avec scoreMaximum et label) d’un coup. Tu n’auras plus qu’à y poster les scores via AGS (chapitre 10.3) : le Deep Linking a préparé le terrain de l’AGS.

⚠️ Piège — Renvoyer la réponse en clair (un simple JSON POST) ou avec un JWT non signé. La réponse Deep Linking doit être un JWT signé par ta clé privée : c’est ce qui prouve à la plateforme que la sélection vient bien de ton outil (et pas d’un tiers qui forgerait des content_items pointant ailleurs). Sans signature valide, la plateforme rejette — et parfois silencieusement (l’enseignant revient sur une page vide). Oublier de ré-émettre data est l’autre grand classique : la plateforme ne retrouve pas son contexte et abandonne.

🔌 Côté intégration — Deep Linking, c’est l’ergonomie qui fait gagner l’appel d’offres. Un concurrent qui oblige l’enseignant à copier des URLs perd face à un outil où l’on clique « Ajouter depuis X », on choisit dans un beau catalogue, et l’activité plus sa colonne de note apparaissent d’un coup. Les évaluateurs de LMS testent exactement ce parcours. C’est aussi un critère de la certification Deep Linking.

🧭 Sur FormaCampus — L’enseignant de 6e A clique « Ajouter un exercice FormaCampus » dans son Moodle. Le studio reçoit un LtiDeepLinkingRequest, lit accept_types (ltiResourceLink accepté) et affiche son catalogue filtré sur « Mathématiques 6e ». L’enseignant choisit « Calcul mental — fractions ». Le studio renvoie un LtiDeepLinkingResponse signé, avec un ltiResourceLink portant custom.exerciceId = ex-4815 et un lineItem (scoreMaximum: 20). Moodle crée l’activité et la colonne « Calcul mental — fractions » dans le carnet. Au chapitre suivant, le studio remplira cette colonne.

📚 La spec — Deep Linking est spécifié par LTI Deep Linking (1EdTech). Le lancement porte .../lti/claim/message_type = LtiDeepLinkingRequest et .../lti/claim/deep_linking_settings ; la réponse est un JWT LtiDeepLinkingResponse portant .../lti-dl/claim/content_items (et .../lti-dl/claim/data). Les types d’items et leurs champs exacts (dont le sous-objet lineItem) sont normés — vois 1edtech.org.

✏️ Exercices

Exercice 1 — Lis les règles. Tu reçois un lancement dont deep_linking_settings contient "accept_types": ["ltiResourceLink"] et "accept_multiple": false. Que peux-tu (et ne peux-tu pas) renvoyer ?

✅ Solution

Tu peux renvoyer un seul item, de type ltiResourceLink. Tu ne dois pas : renvoyer plusieurs items (accept_multiple est false), ni renvoyer un link, file, html ou image (non listés dans accept_types). Ton interface doit donc limiter la sélection à un exercice et ne proposer que des activités relançables. Et ta réponse doit ré-émettre le data reçu, dans un JWT signé.

Exercice 2 — Complète l’item. Tu veux que l’exercice choisi crée aussi sa colonne de note (max 20) dans le carnet, et qu’au relancement ton outil sache qu’il s’agit de l’exercice ex-4815 sur les fractions. Écris le content_item.

✅ Solution

{ "type": "ltiResourceLink", "title": "Calcul mental - fractions", "url": "https://studio.formacampus.fr/lti/launch", "custom": { "exerciceId": "ex-4815", "chapitre": "fractions" }, "lineItem": { "scoreMaximum": 20, "label": "Calcul mental - fractions", "resourceId": "ex-4815" } }

Le sous-objet lineItem demande la création de la colonne (avec scoreMaximum et label) ; le custom transporte exerciceId et chapitre, que tu reliras dans le claim .../lti/claim/custom au relancement (LtiResourceLinkRequest) pour ouvrir directement le bon exercice.

🧠 Quiz de révision

1. Comment reconnaît-on un lancement Deep Linking ?

Au claim .../lti/claim/message_type qui vaut LtiDeepLinkingRequest (au lieu de LtiResourceLinkRequest), accompagné du claim .../lti/claim/deep_linking_settings.

2. Que contient deep_linking_settings d’essentiel ?

Notamment deep_link_return_url (où POSTer ta réponse), accept_types (les types d’items acceptés), accept_multiple, et data (jeton opaque à ré-émettre tel quel).

3. Qu’est-ce qu’un LtiDeepLinkingResponse, et qui le signe ?

C’est la réponse de ton outil : un JWT signé par la clé privée de l’OUTIL, avec message_type = LtiDeepLinkingResponse et le claim .../lti-dl/claim/content_items. Il est POSTé au deep_link_return_url.

4. Quels sont les types de content_items ?

ltiResourceLink (activité relançable), link (lien simple), file (fichier), html (fragment HTML), image (image). Le plus courant est ltiResourceLink.

5. Comment Deep Linking prépare-t-il l’AGS ?

Un ltiResourceLink peut porter un sous-objet lineItem : la plateforme crée alors la colonne de note en même temps que l’activité. L’AGS n’aura plus qu’à poster les scores dans cette colonne.


Chapitre suivant : AGS : renvoyer des notes — remplir le carnet du LMS, le service qui crée la vraie valeur.

Last updated on