LTI AGS
Gérer le Gradebook, envoyer des notes, synchroniser les résultats
LTI 1.3 définit le socle : sécuriser les échanges et identifier les utilisateurs. LTI Advantage va plus loin en ajoutant des services qui permettent une intégration plus profonde entre l’outil et le LMS. Cet article détaille le premier de ces services : Assignment and Grade Services (AGS).
L’AGS permet à un outil externe d’interagir avec le gradebook du LMS — créer des colonnes de notes, envoyer les résultats des apprenants, et récupérer les notes telles que le LMS les a enregistrées.
Tous les appels AGS sont sécurisés via le Security Framework OAuth 2.0 décrit en première section.
Framework de sécurité
Dans LTI1.3 il y a la notion de Message, c’est-à-dire un format standardisé pour échanger des informations entre le LMS et l’outil. Lti Advantage ajoute une notion de service qui partagent le même mécanisme pour sécuriser leurs appels HTTP. L’outil va pouvoir bénéficier de ces services en effectuant des requêtes vers le LMS en plus du flow LTI standard décrit dans l’article précédent.
Une fois que le flow standard LTI1.3 est terminé, l’échange entre le LMS et l’outil se fait à l’aide d’un access Token obtenu via le protocole OAuth 2.0. L’outil doit inclure ce token dans les en-têtes de ses requêtes HTTP pour accéder aux services proposés par le LMS. Les services disponibles dépendent des autorisations accordées à l’outil lors de la configuration de l’intégration.
Lors de la registration, l’outils doit demander l’url pour obtenir un access token, c’est à dire l’url du service d’autorisation du LMS. Cette url est ensuite utilisée pour obtenir un access token.
Le flux se déroule en deux étapes :
- L’outil construit et signe un JWT avec sa clé privée
- L’outil poste ce JWT au token endpoint du LMS et reçoit en retour un access_token
Étape 1 — Construire le client_assertion
L’outil crée un JWT qu’il signe lui-même avec sa clé privée RSA (la même que celle déclarée lors de la registration). Ce JWT s’appelle le client_assertion.
Header :
{
"alg": "RS256",
"typ" : "JWT",
}
Payload :
{
"iss": "tool.com",
"sub": "Sfc6HFnwHAx4Tuv",
"aud": "http://localhost/mod/lti/token.php",
"iat": 1775400958,
"exp": 1775401018,
"jti": "a3f1c2d4-e5b6-7890-abcd-ef1234567890"
}
iss: L’identifiant de l’outilsub: Le client idaud: L’URL du service d’autorisation du LMSiat: La date de création du JWT (Timestamp)exp: La date d’expiration du JWT (Timestamp)jti: Un identifiant unique pour le JWT
Étape 2 — Obtenir le Bearer token
L’outil envoie une requête POST au token endpoint du LMS avec le client_assertion dans le corps de la requête. Si la requête est valide, le LMS renvoie un access_token que l’outil peut utiliser pour accéder aux services protégés.
Exemple de requête :
POST http://localhost/mod/lti/token.php
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6Im1vbi1raWQifQ...
&scope=https://purl.imsglobal.org/spec/lti-ags/scope/score
Dans cet exemple http://localhost/mod/lti/token.php correspond à l’URL du service d’autorisation du LMS fournie au moment de la registration.
Nous verrons la notion de scope dans la section suivante, elle permet de définir les autorisations accordées à l’outil pour accéder aux services du LMS.
Vous trouverez plus de détails dans la spécification sur la sécurité ici.
Assignment and Grade Services (AGS)
la plupart des LMS proposent un GradeBook c’est-à-dire un endroit où sont centralisées toutes les notes de tous les apprenants. Il peut-être par cours, dans ce cas le gradebook présente les notes de toutes les activités du cours. Lorsqu’un outil externe propose du contenu tel qu’un quizz, il doit pouvoir envoyer les résultats des apprenants vers ce gradebook.
C’est ce que propose l’AGS :
- un service pour créer et gérer les LineItems, c’est-à-dire les colonnes du gradebook, ce service se nomme
LineItem service - un service pour envoyer les Scores, c’est-à-dire la note brute, ce service se nomme
Score Service - un service pour récupérer les Resultats. (Results Service)
claim AGS
La spécification 1EdTEch propose d’ajouter cette iri au message LTI Launch https://purl.imsglobal.org/spec/lti-ags/claim/endpoint.
Par exemple si l’administrateur à autorisé l’outil à utiliser l’AGS,

l’id token devient
{
"nonce": "32d5072797ec4703a23433996f85c3ea61b3e5ff30f311f18c518cb87ec90090",
"iat": 1775395730,
"exp": 1775395790,
"iss": "http://localhost",
"aud": "Sfc6HFnwHAx4Tuv",
"https://purl.imsglobal.org/spec/lti/claim/deployment_id": "1",
"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": "LtiResourceLinkRequest",
"https://purl.imsglobal.org/spec/lti/claim/resource_link": {
"title": "Hello Django LTI",
"description": "",
"id": "1"
},
"given_name": "Admin",
"family_name": "Utilisateur",
"name": "Admin Utilisateur",
"https://purl.imsglobal.org/spec/lti/claim/ext": {
"user_username": "admin",
"lms": "moodle-2"
},
"email": "sebastien@philippot.co",
"https://purl.imsglobal.org/spec/lti/claim/launch_presentation": {
"locale": "fr",
"document_target": "frame",
"return_url": "http://localhost/mod/lti/return.php?course=2&launch_container=5&instanceid=1&sesskey=M4moqhsjEQ"
},
"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-ags/claim/endpoint": {
"scope": [
"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"
],
"lineitems": "http://localhost/mod/lti/services.php/2/lineitems?type_id=1"
}
}
On constate alors qu’a été ajouté
"https://purl.imsglobal.org/spec/lti-ags/claim/endpoint": {
"scope": [
"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"
],
"lineitems": "http://localhost/mod/lti/services.php/2/lineitems?type_id=1"
}
Il y a deux propriétés importantes à noter dans cette section :
-
scope : Il s’agit d’un tableau de chaînes qui définit les autorisations accordées à l’outil. Dans cet exemple, l’outil a la permission de lire les éléments de ligne, les résultats. L”outil peut aussi envoyer des scores, c’est à dire des notes brutes. Ces scopes déterminent les actions que l’outil peut effectuer sur les données du gradebook du LMS. Par exemple, si l’outil a le scope
lineitem.readonly, il peut lire les éléments de ligne mais ne peut pas les modifier. Si l’outil a le scopescore, il peut envoyer des scores (notes) pour les étudiants. -
lineitems : C’est l’URL proposée par le LMS, qui permet à l’outil d’accéder aux éléments de ligne spécifiques pour le cours. Cela permet à l’outil de récupérer et de modifier les notes des étudiants dans le gradebook du LMS. c’est la collection de toutes les colonnes du gradebook pour ce cours. L’outil peut y lister ou créer des colonnes.
Si l’enseignant autorise à son tour l’outil à utiliser l’AGS, la propriété lineItem est ajoutée.

"https://purl.imsglobal.org/spec/lti-ags/claim/endpoint": {
"scope": [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"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"
],
"lineitems": "http://localhost/mod/lti/services.php/2/lineitems?type_id=1",
"lineitem": "http://localhost/mod/lti/services.php/2/lineitems/2/lineitem?type_id=1"
}
LineItem est l’URL d’une colonne spécifique du gradebook, c’est à dire d’un élément de ligne. L’outil peut y accéder pour récupérer ou modifier les notes des étudiants pour cette colonne spécifique.
Pour manipuler des LineItems ou des LineItem l’outil doit envoyer une requete HTTP avec un header d’autorisation contenant un token d’accès (access token) obtenu via le protocole OAuth 2.0. Le token d’accès doit inclure les scopes appropriés pour les actions que l’outil souhaite effectuer sur les LineItems ou LineItem. Les méthode HTTP autorisée dépendent des scopes accordés à l’outil.
Lorsque le scope contient readonly, l’outil ne peut effectuer que des requêtes de type GET. Si readonly n’est pas présent, l’outil peut effectuer des requêtes de type POST, PUT et DELETE selon les besoins.
Par exemple pour les scopes concernant les LineItems :
| Scope | Méthode HTTP |
|---|---|
https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly | GET |
https://purl.imsglobal.org/spec/lti-ags/scope/lineitem | POST |
https://purl.imsglobal.org/spec/lti-ags/scope/lineitem | PUT |
https://purl.imsglobal.org/spec/lti-ags/scope/lineitem | DELETE |
Pour avoir plus d’information sur les requêtes à effectuer 1EdTTech met a disposition une documentation au format OpenAPI avec Swagger ui , disponible ici.
Pour plus de détails sur chaque requêtes la spécification est disponible ici
Score service
Dans cette partie nous allons voir comment envoyer un score au LMS, soit après avoir créer une colonne supplémentaire à l’aide de lineItems soit en utilisant une colonne existante via lineItem.
Un score est plus complexe qu’une simple valeur numérique. En effet, si l’outil envoie seulement une note alors le LMS peut ne pas être en mesure de l’interpréter correctement. Que signifie avoir eu 18 à un devoir ? Si le devoir est noté sur 20 alors 18 correspond à une très bonne note, mais si le devoir est noté sur 100 alors 18 correspond à une note très faible. C’est pour cela que le service de score permet d’envoyer des informations supplémentaires telles que la note maximale, le progrès de l’activité et d’autres propriétés permettant de contextualiser la note.
modèle de données
1EdTech propose les propriétés suivantes pour le service de score :
{
"timestamp": "2023-03-15T12:00:00Z",
"scoreGiven": 15,
"scoreMaximum": 20,
"comment" : "Très bon travail !",
"activityProgress": "Completed",
"userId": "12345",
"gradingProgress": "FullyGraded",
"scoringUserId": "4567890",
"submission": {
"submittedAt": "2023-03-15T12:00:00Z",
"startedAt": "2023-03-15T12:00:00Z"
}
}
timestamp: La date et l’heure à laquelle la note a été attribuéescoreGiven(optionnel) : La note obtenue par l’apprenantscoreMaximum(Obligatoire siscoreGivenest présent) : La note maximale possible pour l’évaluationcomment(optionnel) : Un commentaire facultatif sur la noteactivityProgress(optionnel) : Cette propriété décrit ce que l’apprenant a fait dans l’activité, indépendamment de toute note. Cette propriété ne peut prendre que les suivantes :- Initialized : L’activité a été créée côté outil mais l’apprenant ne l’a pas encore ouverte
- Started : L’apprenant a ouvert l’activité
- InProgress : L’apprenant est en train de travailler sur l’activité
- Submitted : L’apprenant a soumis l’activité, il attend une correction
- Completed : L’apprenant a terminé l’activité. Bien que l’activité soit terminée, la notation peut ne pas être terminée. Par exemple, un devoir peut être terminé mais en attente de correction par l’enseignant.
userId(obligatoire) : L’identifiant de l’utilisateur ayant reçu la notegradingProgress(optionnel) : L’état d’avancement de la notation pour cette note. Cette propriété ne peut prendre que les suivantes :- NotReady: L’activité n’est pas encore prête à être notée
- Pending : Une note a été calculée mais l’outil la traite encore en interne avant de l’envoyer définitivement
- PendingManual : L’activité nécessite une correction manuelle par un enseignant — le LMS ne doit pas encore afficher de note finale
- Failed : La tentative de notation a échoué, le LMS doit ignorer cette note
- FullyGraded : La note a été entièrement attribuée et est maintenant finale, le LMS peut afficher la note dans le
Gradebook
scoringUserId(optionnel) : L’identifiant de l’utilisateur ayant attribué la notesubmission(optionnel) : Métadonnées sur la tentative de l’apprenant. Contient deux propriétés :startedAt: La date et l’heure à laquelle l’apprenant a commencé à travailler sur l’activitésubmittedAt: La date et l’heure à laquelle l’apprenant a soumis son travail
activityProgress et gradingProgress fonctionnent ensemble et donne du sens sur les interaction de l’apprenant avec l’activité.
| Situation | activityProgress | gradingProgress |
|---|---|---|
| L’apprenant commence le quizz | Started | NotReady |
| L’apprenant soumet, correction auto en cours | Submitted | Pending |
| Correction auto terminée, note affichable | Completed | FullyGraded |
| L’apprenant soumet un devoir à corriger manuellement | Submitted | PendingManual |
| L’enseignant a corrigé le devoir | Completed | FullyGraded |
LTI offre ici un début de solution pour envoyer des traces d’apprentissage. En effet, grace à la propriété activityProgress l’outil peut envoyer des informations sur l’avancement de l’activité. Par exemple, un outil de lecture de vidéo peut envoyer une trace lorsque l’apprenant commence à regarder la vidéo (Started), lorsqu’il regarde la moitié de la vidéo (InProgress) et lorsqu’il termine de regarder la vidéo (Completed). Ces traces d’apprentissage peuvent ensuite être utilisées par le LMS pour suivre l’engagement des apprenants avec le contenu et pour fournir des analyses sur les activités d’apprentissage. C’est moins complet que des standards tels que XAPI ou Caliper mais c’est un début pour permettre aux outils d’envoyer des données d’engagement au LMS.
Envoie du score
Nous avons vu précédement que lorsque un administrateur autorise un outil à envoyer des scores, des propriétés supplémentaire étaient envoyés dans l’id token dont cet exemple :
"https://purl.imsglobal.org/spec/lti-ags/claim/endpoint": {
"scope": [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"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"
],
"lineitems": "http://localhost/mod/lti/services.php/2/lineitems?type_id=1",
"lineitem": "http://localhost/mod/lti/services.php/2/lineitems/2/lineitem?type_id=1"
}
on voit que le LMS renvoie une url pour lineitem et une url pour lineitems. L’outil peut choisir d’envoyer le score sur une colonne spécifique du gradebook en utilisant l’url de lineitem ou d’envoyer le score sur une nouvelle colonne en utilisant l’url de lineitems.
Le scope https://purl.imsglobal.org/spec/lti-ags/scope/score doit être présent. Le scope d’un score autorise seulement les requête en POST, il n’est donc pas permis à un outils de lire (Http Get) un score depuis le LMS.
Le score s’envoie via un POST sur l’URL du lineitem suivi de /scores :
POST http://localhost/mod/lti/services.php/2/lineitems/2/lineitem/scores?type_id=1
Authorization: Bearer <access_token>
Content-Type: application/vnd.ims.lis.v1.score+json
Le content-type est un peu particulier car il doit être au format application/vnd.ims.lis.v1.score+json.
Le Score Service se complète avec le Submission Review Message, une spec complémentaire qui permet à l’enseignant de lancer l’outil directement depuis le gradebook pour corriger une soumission PendingManual. Ce mécanisme est détaillé dans un article dédié.
Result service
Dans la section précédente, nous avons vu que c’est l’outils qui envoie le score. Cependant, le LMS doit avoir le contrôle de ce score car ça reste lui qui gère les résultats des apprenants. Le LMS peut décider d’accepter ou de rejeter le score envoyé par l’outil, et il peut également mettre à jour le score ultérieurement si nécessaire.
Prenons l’exemple d’un apprenant qui travaille sur un devoir d’anglais, l’outil envoie un score de 15/20 pour ce devoir. Cependant, l’enseignant peut ne pas être d’accord avec ce score et décider de le modifier. Par exemple, après avoir pris connaissance du devoir, l’enseignant peut estimer que les erreurs de l’apprenants sont sur des questions non abordés a son cours. Il peut alors décider de ne pas prendre en compte ces erreurs et de mettre à jour le score à 18/20. Il y a donc un déphasage : l’outil conserve 15/20 dans sa base de données alors que le LMS, source de vérité, affiche 18/20 à l’apprenant
Pour résoudre ce problème, 1EdTech propose un service de résultats (Result service) qui permet à l’outil de récupérer les résultats des apprenants depuis le LMS. L’outil peut ainsi synchroniser sa base de données avec les notes réelles du LMS et éviter les problèmes de déphasage.
Modèle de données
{
"id": "http://localhost/mod/lti/services.php/2/lineitems/2/lineitem/results/2",
"scoreOf": "http://localhost/mod/lti/services.php/2/lineitems/2/lineitem?type_id=1",
"userId": "2",
"resultScore": 15,
"resultMaximum": 20,
"comment": "Très bon travail !"
}
id: URL unique du résultat, assignée par le LMSscoreOf: URL du lineitem auquel ce résultat est associéuserId: L’identifiant de l’apprenant — correspond ausubdu JWT de launchresultScore: La note telle que le LMS l’a enregistréeresultMaximum: La note maximale telle que le LMS l’a enregistréecomment(optionnel) : Le commentaire associé à la note
récupération des résultats
L’URL du service résulte directement de l’URL du lineitem — il suffit d’ajouter /results :
GET http://localhost/mod/lti/services.php/2/lineitems/2/lineitem/results?type_id=1
Authorization: Bearer <access_token>
Accept: application/vnd.ims.lis.v2.resultcontainer+json
Pour filtrer sur un seul apprenant, on ajoute le paramètre user_id :
GET http://localhost/mod/lti/services.php/2/lineitems/2/lineitem/results?type_id=1&user_id=2
Authorization: Bearer <access_token>
Accept: application/vnd.ims.lis.v2.resultcontainer+json
Le LMS retourne un tableau de résultats, un par apprenant ayant un score enregistré.
Pour plus de détails la spécification est disponible ici.