7 mars 2026 · 6 min read

LTI Dynamic registration

Enregistrer un outils externe avec seulement une URL

#LTI #e-learning #standard #LMS

LTI Dynamic Registration : automatiser l’enregistrement des outils dans votre LMS

Objectif de la Dynamic Registration

L’étape de registration ( cf : registration ) nécessite une configuration manuelle et un échage d’informations entre l’éditeur de l’outil et l’administrateur du LMS. C’est une source d’erreurs (URL mal formée, paramètres oubliés…) La Dynamic Registration vise à automatiser ce processus l’éditeur de l’outil donne une URL à l’administrateur du LMS et tout se passe automatiquement, la seule action manuelle est de saisir cette URL dans le LMS

Pré requis

LTI 1.3 et la Dynamic Registration reposent sur OpenID Connect, il est donc nécessaire que le LMS supporte ce protocole. Il est donc important de connaître les bases de ce protocole pour comprendre le fonctionnement de la Dynamic Registration. Je vous invite à lire mon article sur OpenID Connect si ce n’est pas déjà fait : OpenID Connect : l’authentification moderne expliquée simplement.

Le flux en quatre étapes

Étape 1 - Initiation depuis le LMS

L’administrateur du LMS saisit l’URL d’enregistrement fournie par l’éditeur de l’outil.

Par exemple dans moodle :

Initiation de la Dynamic Registration dans Moodle

Moodle détecte automatiquement si l’URL saisie correspond à un outil déjà enregistré, et propose alors de le mettre à jour ou d’en créer un nouveau.

Initiation de la Dynamic Registration dans Moodle : mise à jour d'un outil existant

C’est également une fonctionnalité intéressante pour les outils déjà enregistrés : elle permet de mettre à jour leur configuration (scopes, messages supportés…) sans devoir passer par une procédure d’édition fastidieuse. Ou passer d’un outil LTI 1.1 à LTI 1.3.

Cette URL est lancée dans un IFrame (ou un nouvel onglet) par le LMS, qui y ajoute deux paramètres :

  • openid_configuration : l’URL vers la configuration OpenID du LMS
  • registration_token : un jeton à usage unique, valide pendant une heure

Le LMS envoie cette requête à l’URL d’enregistrement, qui doit être gérée par l’outil. C’est le point de départ de la Dynamic Registration.

GET http://localhost:8000/lti/register?openid_configuration=http%3A%2F%2Flocalhost%2Fmod%2Flti%2Fopenid-configuration.php&registration_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImEwMWFhNzE1MWEzOTMxOWUxYTk5In0.eyJzdWIiOiJzQXlqcFhoMzBLQW96eHoiLCJzY29wZSI6InJlZyIsImlhdCI6MTc3ODc3NjczMywiZXhwIjoxNzc4NzgwMzMzfQ.LnIp6Ni2hjJ9td_XNf5kmKrJqa5O6M5si6QaJcMWXPhS7cGRoPVffNIc5I7LrhvYPlpKbbDAY1Y8YCSEnc8YosaORfxCSxNKbvfNTeMejgJyx_thASfmRDflVdJmMdPHDH6gFD8W68jJhYVOJtCueAh-89PPgDeqaJpqa7gxWgoKHY-91pkXi9sVFc3awY75Bn_I2JnKp-C7F-CMvMb-3wnlNLF9u4ssAChpUG6fMvfS1I0nH4VB5lDGfqZDtFHyQHNr7N4MwJ5z6P7tRWYeKQkrGEtgl0U94lJuwggsLwnKxCFkLshcSwPE_oaBPSIG0t340fxsEMPV5vO6QZKDhQ

Dans cette URL on peut voir :

  • l’URL de mon outil en local: http://localhost:8000/lti/register

  • le paramètre openid_configuration qui pointe vers la configuration du LMS : http://localhost/mod/lti/openid-configuration.php

  • le paramètre registration_token qui contient un JWT signé par le LMS, à usage unique

    {
    "sub": "sAyjpXh30KAozxz",
    "scope": "reg",
    "iat": 1778776733,
    "exp": 1778780333
    }
    • sub : un identifiant de session unique pour ce processus d’enregistrement
    • scope : la portée “reg” qui indique que ce token est destiné à la registration
    • iat et exp : les timestamps d’émission et d’expiration du token

Étape 2 - Découverte de la configuration plateforme

L’outil interroge l’endpoint openid_configuration pour récupérer un document JSON décrivant les capacités du LMS. Avant d’aller plus loin, il doit vérifier que le domaine de cet endpoint correspond bien à celui de l’issuer déclaré dans le document. C’est une protection contre les attaques d’usurpation d’identité.

Le document retourné par le LMS contient des informations OpenID standards (endpoints d’authentification, JWKS, token…) enrichies d’un bloc LTI spécifique.

Par exemple, voici la configuration retournée par Moodle :

{
"issuer": "http://localhost",
"token_endpoint": "http://localhost/mod/lti/token.php",
"token_endpoint_auth_methods_supported": ["private_key_jwt"],
"token_endpoint_auth_signing_alg_values_supported": ["RS256"],
"jwks_uri": "http://localhost/mod/lti/certs.php",
"authorization_endpoint": "http://localhost/mod/lti/auth.php",
"registration_endpoint": "http://localhost/mod/lti/openid-registration.php",
"scopes_supported": [
"https://purl.imsglobal.org/spec/lti-bo/scope/basicoutcome",
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly",
"https://purl.imsglobal.org/spec/lti-ts/scope/toolsetting",
"openid"
],
"response_types_supported": ["id_token"],
"subject_types_supported": ["public", "pairwise"],
"id_token_signing_alg_values_supported": ["RS256"],
"claims_supported": ["sub", "iss", "name", "given_name", "family_name", "email"],
"https://purl.imsglobal.org/spec/lti-platform-configuration": {
"product_family_code": "moodle",
"version": "5.1.3+ (Build: 20260403)",
"messages_supported": [
{"type": "LtiResourceLinkRequest"},
{"type": "LtiDeepLinkingRequest", "placements": ["ContentArea"]}
],
"variables": [
"basic-lti-launch-request", "ContentItemSelectionRequest", "ToolProxyRegistrationRequest",
"Context.id", "Context.title", "Context.label", "Context.id.history", "Context.sourcedId",
"Context.longDescription", "Context.timeFrame.begin", "CourseSection.title",
"CourseSection.label", "CourseSection.sourcedId", "CourseSection.longDescription",
"CourseSection.timeFrame.begin", "CourseSection.timeFrame.end", "ResourceLink.id",
"ResourceLink.title", "ResourceLink.description", "User.id", "User.username",
"Person.name.full", "Person.name.given", "Person.name.family", "Person.email.primary",
"Person.sourcedId", "Person.name.middle", "Person.address.street1", "Person.address.locality",
"Person.address.country", "Person.address.timezone", "Person.phone.primary",
"Person.phone.mobile", "Person.webaddress", "Membership.role", "Result.sourcedId",
"Result.autocreate", "BasicOutcome.sourcedId", "BasicOutcome.url", "Moodle.Person.userGroupIds"
]
}
}

Le lms montre ici à l’outils ses capacités, ce qu’il accepte ou non grace à la propriété scope, ici on peut voir que Moodle accepte AGS, NPRS, les variables de subsititutions disponibles (vous trouvrez la liste exhaustives ici).

Étape 3 - Enregistrement de l’outil

Une fois la configuration du LMS récupérée et validée, l’outil envoie un POST vers le registration_endpoint, avec le token comme Bearer dans l’en-tête Authorization. Le corps de la requête est un objet JSON qui combine la configuration OpenID standard et un bloc LTI spécifique :

{
"response_types": ["id_token"],
"application_type": "web",
"client_name": "LTI Hello",
"initiate_login_uri": "http://localhost:8000/lti/login/",
"grant_types": ["implicit", "client_credentials"],
"jwks_uri": "http://localhost:8000/lti/jwks/",
"token_endpoint_auth_method": "private_key_jwt",
"redirect_uris": ["http://localhost:8000/lti/launch/"],
"scope": "https://purl.imsglobal.org/spec/lti-ags/scope/lineitem ...",
"https://purl.imsglobal.org/spec/lti-tool-configuration": {
"domain": "localhost:8000",
"target_link_uri": "http://localhost:8000/lti/launch/",
"claims": ["iss", "sub", "name", "email"],
"messages": [{
"type": "LtiDeepLinkingRequest",
"target_link_uri": "http://localhost:8000/lti/launch/",
"label": "Ajouter un exercice"
}],
"description": "Exercices Python interactifs"
}
}
  • Partie OpenID standard (commune à tout client OpenID) :

    • response_types: [“id_token”] : l’outil s’attend à recevoir un token JWT en réponse au login
    • application_type: “web”:c’est une application web (pas mobile)
    • grant_types: [“implicit”, “client_credentials”] : implicit pour le flow de launch LTI, client_credentials pour appeler les services (AGS, NRPS…)
    • token_endpoint_auth_method: “private_key_jwt” :l’outil s’authentifie auprès du LMS en signant avec sa clé privée RSA
    • initiate_login_uri :l’URL que Moodle appellera pour démarrer le flow OpenID Connect lors d’un launch
    • redirect_uris :les URLs autorisées comme destination finale après authentification
    • jwks_uri :où Moodle peut récupérer la clé publique de l’outil pour vérifier ses signatures
    • scope : les services LTI auxquels l’outil demande accès : AGS (gestion des notes) et NRPS (liste des membres)
  • Partie LTI spécifique (lti-tool-configuration) :

    • domain : le domaine de l’outil
    • target_link_uri :l’URL de lancement par défaut quand Moodle exécute un launch LTI
    • claims : les infos utilisateur que l’outil demande dans chaque id_token (name, email…)
    • messages : les types de launch supportés en plus du LtiResourceLink implicite ; ici le Deep Linking avec son URL et son label dans l’interface Moodle
    • description : texte affiché à l’admin dans Moodle lors de la révision

Le LMS répond :

{
"client_id": "KIbBCi9fyE5Rwkz",
"response_types": [
"id_token"
],
"jwks_uri": "http://localhost:8001/lti/jwks/",
"initiate_login_uri": "http://localhost:8001/lti/login/",
"grant_types": [
"client_credentials",
"implicit"
],
"redirect_uris": [
"http://localhost:8001/lti/launch/"
],
"application_type": "web",
"token_endpoint_auth_method": "private_key_jwt",
"client_name": "LTI Hello",
"logo_uri": "",
"scope": "https://purl.imsglobal.org/spec/lti-ags/scope/score https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly https://purl.imsglobal.org/spec/lti-ags/scope/lineitem https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly",
"https://purl.imsglobal.org/spec/lti-tool-configuration": {
"version": "1.3.0",
"deployment_id": "15",
"target_link_uri": "http://localhost:8001/lti/launch/",
"domain": "localhost:8001",
"description": "Exercices Python interactifs",
"messages": [
{
"type": "LtiDeepLinkingRequest",
"target_link_uri": "http://localhost:8001/lti/launch/"
}
],
"claims": [
"sub",
"iss",
"name",
"family_name",
"given_name",
"email"
]
}
}```
### Étape 4 : Clôture et activation
Une fois l'enregistrement réalisé (avec succès ou non), l'outil notifie le LMS via un `window.postMessage` :
```javascript
(window.opener || window.parent).postMessage(
{ subject: 'org.imsglobal.lti.close' },
'*'
);

Ce signal déclenche la fermeture de l’IFrame et un rafraîchissement de la liste des outils côté LMS. L’outil apparaît alors en état “en attente” : un administrateur doit le réviser, éventuellement modifier certains paramètres, et l’activer pour le rendre disponible aux utilisateurs.

Outil en attente d'activation dans Moodle

Conclusion

La Dynamic Registration réduit une source d’erreur lors de la configuration manuelle En automatisant cet échange, la Dynamic Registration déplace la responsabilité de la configuration vers l’éditeur de l’outil, qui connaît mieux ce dont son outil a besoin. L’administrateur du LMS n’a plus qu’à valider. C’est aussi ce qui rend possible les mises à jour transparentes : quand un outil ajoute le support d’AGS ou de Deep Linking, l’administrateur peut re-lancer la procédure depuis la même URL et récupérer la configuration à jour sans reconfigurer manuellement.

La Dynamic Registration est un échange de configuration, pas un contrat. La spécification 1EdTech l’affirme explicitement. Ce que l’outil demande (scopes, claims, variables) n’est qu’une déclaration d’intention. L’administrateur du LMS peut ensuite modifier, restreindre ou étendre ces paramètres à tout moment.

Sources :

Partager