Chapitre 10.4 — NRPS : lire le roster
⏱️ TL;DR — NRPS (Names and Role Provisioning Services) laisse ton outil lire la liste des membres d’un cours — le roster — et leurs rôles, sans que l’enseignant ressaisisse quoi que ce soit. Le lancement livre l’endpoint dans le claim
.../lti-nrps/claim/namesroleservice={ "context_memberships_url": "URL", "service_versions": [...] }. On faitGET {context_memberships_url}(avec unaccess_tokende scope.../lti-nrps/scope/contextmembership.readonly) et on reçoit un conteneurmembers: pour chaque membre,user_id,roles,status, et — si la plateforme les partage —nameetLinkavecrel="next"). Cas d’usage : pré-remplir la classe, afficher un tableau de suivi. Mais un roster, ce sont des données personnelles de mineurs : ne lis et ne stocke que le nécessaire (RGPD).
🎯 Objectifs
- Lire le claim
namesroleserviceet appelercontext_memberships_url. - Interpréter le conteneur
members(user_id,roles,status,name/email). - Gérer la pagination (en-tête
Link,rel="next"). - Décider quelles données lire et conserver — et lesquelles laisser (confidentialité).
Le problème : connaître la classe
Ton outil affiche un tableau de suivi à l’enseignant : une ligne par élève, avec sa progression. Mais au premier lancement, ton outil ne connaît que l’utilisateur qui vient de cliquer (son sub). Comment lister toute la classe sans que l’enseignant tape 28 noms à la main ?
NRPS répond : ton outil demande le roster à la plateforme. Il obtient la liste des membres du contexte (le cours), avec leurs rôles et leur statut. Tu peux alors pré-remplir ta classe, préparer une ligne par élève, afficher qui est enseignant et qui est apprenant — le tout avant même que les élèves se connectent.
Le claim namesroleservice
Comme pour AGS, l’endpoint arrive dans le id_token du lancement :
{
"https://purl.imsglobal.org/spec/lti-nrps/claim/namesroleservice": {
"context_memberships_url": "https://moodle.ecole.fr/mod/lti/services.php/CtxMemberships.php/2?type=Membership",
"service_versions": ["2.0"]
}
}context_memberships_url: l’URL du roster de ce cours. C’est elle qu’on interroge.service_versions: les versions de NRPS supportées par la plateforme (ici2.0).
Lire le roster
Un GET, avec un access_token de scope .../lti-nrps/scope/contextmembership.readonly :
GET /mod/lti/services.php/CtxMemberships.php/2?type=Membership HTTP/1.1
Host: moodle.ecole.fr
Authorization: Bearer eyJ0eXAi...
Accept: application/vnd.ims.lti-nrps.v2.membershipcontainer+jsonLa réponse est un conteneur de membres :
{
"id": "https://moodle.ecole.fr/mod/lti/services.php/CtxMemberships.php/2",
"context": {
"id": "course-9271",
"label": "MATH-6A",
"title": "Mathematiques 6e A"
},
"members": [
{
"user_id": "u-2342",
"roles": ["http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"],
"status": "Active",
"name": "Camille Martin",
"email": "camille.martin@ecole.fr"
},
{
"user_id": "u-1088",
"roles": ["http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor"],
"status": "Active",
"name": "Sofia Nkosi"
},
{
"user_id": "u-7751",
"roles": ["http://purl.imsglobal.org/vocab/lis/v2/membership#Learner"],
"status": "Inactive"
}
]
}Décryptage :
- Le conteneur porte un
context(le cours :id,label,title) et un tableaumembers. - Chaque membre a :
user_id: l’identifiant stable de l’utilisateur chez la plateforme. C’est le même que lesubreçu quand cet utilisateur lance ton outil (chapitre 9.5). C’est la clé pour recoller roster et notes.roles: un tableau d’URIs de rôles (mêmes valeurs qu’au lancement :...#Learner,...#Instructor…). Un membre peut cumuler plusieurs rôles.status:Active,InactiveouDeleted. Un élève désinscrit apparaîtInactive/Deleted.name/email: présents seulement si la plateforme accepte de les partager (voir plus bas). Dans l’exemple, l’enseignant Sofia n’a pas d’emailpartagé, et l’élèveu-7751n’a ni nom ni e-mail.
⚠️ Piège — Supposer que
nameetuser_id,rolesetstatus. Un outil qui plante faute d’e-mail est un outil qui ne passe pas la revue de sécurité d’une académie. Traitename/user_idcomme identifiant.
⚠️ Piège — Recoller roster et notes via l’e-mail ou le nom. Utilise
user_id(= lesubdu lancement). L’e-mail change, manque, ou n’est pas partagé ; le nom n’est pas unique.user_idest la seule clé fiable et stable.
Filtrer et paginer
Deux paramètres utiles sur context_memberships_url :
- Filtre par rôle :
?role=...#Instructorpour ne récupérer que les enseignants (ou?role=...#Learnerpour les élèves). Pratique et économe. - Pagination : un gros cours renvoie les membres par pages. La page suivante n’est pas un numéro dans le JSON : c’est un en-tête HTTP
Linkavecrel="next".
HTTP/1.1 200 OK
Content-Type: application/vnd.ims.lti-nrps.v2.membershipcontainer+json
Link: <https://moodle.ecole.fr/mod/lti/services.php/CtxMemberships.php/2?rlid=res-4815&page=2>; rel="next"
{ "id": "...", "context": { }, "members": [ ] }Tu lis la page, puis, tant qu’il y a un Link ... rel="next", tu suis l’URL fournie et tu concatènes les members. Quand l’en-tête next disparaît, tu as tout le roster.
💡 Réflexe — Suis toujours la pagination. Un dev qui lit « la première page » croit avoir 20 élèves alors que la classe en compte 45. Boucle sur
rel="next"jusqu’à épuisement, et n’invente pas de?page=toi-même : utilise l’URL exacte donnée dans l’en-têteLink(elle peut porter des paramètres opaques).
Cas d’usage
| Besoin | Comment NRPS aide |
|---|---|
| Pré-remplir la classe | Récupérer tous les Learner Active pour préparer une ligne de suivi par élève, avant leurs connexions. |
| Tableau de bord enseignant | Croiser le roster (NRPS) avec les notes (AGS) via user_id = clé : afficher « qui a fait quoi, avec quel score ». |
| Afficher la liste | Montrer les membres et leurs rôles (distinguer profs et élèves). |
| Nettoyer | Marquer Inactive/Deleted les élèves désinscrits, ne plus leur pousser de contenu. |
🔒 Confidentialité — Un roster de cours scolaire, ce sont des données personnelles de mineurs. Le partage de
name/user_idsuffit à ton usage (recoller les notes), ne demande pas et ne stocke pas les noms/e-mails. Cette discipline relève du RGPD — et une académie la vérifie avant de te déployer.
🔌 Côté intégration — NRPS transforme l’expérience enseignant : au lieu d’attendre que chaque élève se connecte pour « exister » dans ton outil, la classe est là dès le premier lancement. Combiné à l’AGS, ça donne un vrai tableau de suivi (roster × notes) — l’argument qui fait dire à un chef d’établissement « celui-là, on le garde ». La certification NRPS vérifie que tu gères correctement la pagination, les rôles et l’absence de
name/
🧭 Sur FormaCampus — Au lancement enseignant (rôle
#Instructor), le studio litnamesroleservice, obtient unaccess_token(scopecontextmembership.readonly) etGETle roster de 6e A. Il récupère 28LearnerActive(dont beaucoup sans e-mail — la plateforme protège les mineurs), boucle surrel="next"pour la 2ᵉ page, et pré-remplit son tableau : une ligne par élève, indexée suruser_id. Quand les scores remontent via AGS (10.3), le studio les place en face du bonuser_id. L’enseignant voit sa classe complète, avec ou sans notes, sans avoir tapé un seul nom. Et le studio ne conserve pas les e-mails, qu’il n’utilise pas.
📚 La spec — NRPS est spécifié par LTI Names and Role Provisioning Services (1EdTech). Le claim
.../lti-nrps/claim/namesroleservice(context_memberships_url,service_versions), le conteneurmembers(user_id,roles,status,name/application/vnd.ims.lti-nrps.v2.membershipcontainer+json, le filtreroleet la pagination par en-têteLinksont normés. Scope :.../lti-nrps/scope/contextmembership.readonly. Détails sur1edtech.org.
✏️ Exercices
Exercice 1 — Lis le roster. Dans le conteneur members de l’exemple, combien d’élèves actifs ton outil doit-il afficher, et qu’utilises-tu comme identifiant pour chacun ?
✅ Solution
Un seul élève actif à afficher : u-2342 (Camille), qui a ...#Learner et status: "Active". u-1088 est enseignant (#Instructor), pas un élève. u-7751 est un Learner mais Inactive (désinscrit) — à ne pas afficher comme élève actif. L’identifiant est user_id (u-2342), pas l’e-mail ni le nom.
Exercice 2 — Pagination. Ta première requête NRPS renvoie 20 membres et un en-tête Link: <...page=2>; rel="next". La classe fait 45 élèves. Que fais-tu ?
✅ Solution
Tu n’as pas tout le roster. Tu dois suivre l’URL exacte donnée dans l’en-tête Link (rel="next"), faire le GET suivant (avec le même bearer), concaténer ses members, et répéter tant qu’un en-tête rel="next" est présent. Quand il disparaît, tu as les 45. Ne fabrique pas toi-même ?page=3 : utilise l’URL fournie, qui peut contenir des paramètres opaques.
Exercice 3 — Minimisation. La plateforme partage name et email de mineurs. Ton outil n’a besoin que de recoller les notes au bon élève. Que lis-tu, que stockes-tu ?
✅ Solution
Pour recoller les notes, user_id suffit (c’est la clé partagée avec l’AGS). Tu peux lire le conteneur, mais tu ne conserves que user_id (et éventuellement roles/status pour l’affichage). Tu ne stockes pas name/email, dont tu n’as pas l’usage : c’est le principe de minimisation du RGPD, particulièrement critique pour des mineurs, et un point vérifié par les académies avant déploiement.
🧠 Quiz de révision
1. Dans quel claim, et à quelle URL, lit-on le roster ?
Dans le claim .../lti-nrps/claim/namesroleservice, champ context_memberships_url. On y fait un GET avec le scope .../lti-nrps/scope/contextmembership.readonly.
2. Que contient chaque membre du conteneur members ?
members ?user_id (identifiant stable), roles (tableau d’URIs), status (Active/Inactive/Deleted), et si partagés name/email. user_id correspond au sub du lancement de ce membre.
3. Comment gère-t-on un gros roster ?
Par pagination : la page suivante est donnée dans l’en-tête HTTP Link avec rel="next". On suit cette URL jusqu’à ce qu’il n’y ait plus de next. On peut aussi filtrer par ?role=....
4. Peut-on compter sur name et email ?
name et email ?Non. Ils sont optionnels et souvent absents (protection des mineurs, réglage de confidentialité de la plateforme). On traite name/email comme absents par défaut et on n’utilise que user_id comme identifiant.
5. Quelle donnée relie roster (NRPS) et notes (AGS) ?
Le user_id du membre (NRPS) est le même que le userId du Score et le sub du lancement (AGS). C’est la clé qui permet d’afficher, en face de chaque élève, sa note.
Chapitre suivant : Sécurité & conformité — clés, scopes, rotation, et la certification 1EdTech qui ouvre les marchés.