CONECTORES / LTI 1.3
P2LRN LTI 1.3 Module
P2LRN includes a universal, self-hosted LTI 1.3 provider: it validates OIDC/JWT releases, publishes JWKS, offers catalog and Deep Linking, runs the same Player, persists state per learner/attempt, and can deliver grades via AGS. It is not a separate plugin for each LMS nor is it part of the course ZIP.
LTI 1.3 Provider Source Code
The technical ZIP includes the current code of integration/lms: cryptographic provider, HTTP server, SQLite store, AGS client, release and testing contracts. It also includes the Host Adapter needed to border with Player. It is not a specific Moodle/Canvas/Sakai/Chamilo/Open edX plugin nor a precompiled binary.
Node.js 22.13+ and compiled Toolkit and Player distributions. A real deployment also requires a persistent RSA key, private storage, and a trusted HTTPS proxy.
node integration/lms/lti-server.mjs starts the provider after setting its environment variables. By default it listens in loopback.
The provider includes JWT validation, issuer/audience, nonce/state, replay protection, Deep Linking, persistence, Player, AGS OAuth and isolation between institutions.
p2lrn.org It is not a multi-institution LTI gateway to register directly to an LMS. Each deployment must host the provider in its own HTTPS URL, persist its keys, and explicitly register its trusted platforms.
Architecture: single player
The LMS maintains learners, teachers, registrations and gradebooks. The gateway verifies the identity and selects the published content; The Host Adapter manages loading and saving of state, events and notes. Player always opens the same .p2lrn, regardless of the LMS manufacturer.
OIDC – Secure Boot and Launch
- The administrator explicitly registers the platform using
issuer,client_id, allowed deployments, authorization/token URLs and trusted JWKS keys. /lti/logincreate a transaction withstateandnonceunique and short-lived./lti/launchvalidates the RS256 signature and claimsiss,aud/azp,exp,iat, version, type,deployment_id,target_link_uriand authorized binding.stateandnonceThey are consumed to block replay before creating the runtime session.
These checks live in the backend. The browser only receives a limited session for already authorized content.
JWKS and public keys
The provider publishes its keyring on /lti/jwks and sign Deep Linking responses with your persistent RSA key. To validate the LMS, it only uses keys belonging to trusted administrative records; a URL received from an unknown JWT does not become a trusted source.
The private keys, administrative token, SQLite, and package catalog remain off the public web and outside of each .p2lrn.
Deep Linking: choose course and lesson
The server implements protected catalog and selector. A teacher can choose a published course, unit, or activity and the provider returns a ltiResourceLink signed with a p2lrn_binding_id opaque tenant-bound, registration, deployment, package, contentRoot and entity.
packageId + contentRoot + entityId identifies content and revision.
The opaque link avoids relying solely on resource_link.id, which can change when copying courses.
An administrator can create an authorized manual binding using POST /lti/admin/bindings and configure its opaque value as a custom LMS parameter.
Neither the teacher nor the learner can choose an arbitrary URL or entity to bypass the authorized catalog.
AGS: submit grades
The provider implements Assignment and Grade Services. The browser can report an observation, but an official note is only sent after the server validates it as authoritative. POST /lti/admin/grades records the decision and uses a persistent, idempotent outbox for OAuth2 submission.
With scope lineitem.readonly can locate and reuse a compatible column of the same resourceLinkId, respecting your scoreMaximum.
A new one is only created when the LMS explicitly granted write scope lineitem.
The faults remain in /lti/admin/ags/pending and can be retried without accepting redirections or destinations outside the registered LMS.
NRPS: roles and enrollments (optional)
NRPS remains optional and not currently implemented in this module. The LTI release roles are validated within the signed claims. learner roster synchronization should not be announced through NRPS until that service is implemented and tested.
Current provider status
createP2LRNLtiProvider(), createP2LRNLtiServer() and persistent SQLite for logs, deployments, catalog, bindings, transactions, sessions, attempts, status, events and AGS outbox.
JWT signing/verification, state/nonce/replay, catalog, selector, and signed Deep Linking response.
Authorized runtime, loading/saving state and events, intent inspection, OAuth2 AGS, secure lineitem reuse, and persistent retries.
NRPS is not part of this module. Compatibility with a particular installation of Moodle, Canvas, Sakai, Chamilo or Open edX must be validated against the actual LMS version, configuration and policies before using that integration.
The server implements /lti/login, /lti/launch, /lti/deep-link, /lti/deep-link/confirm, /lti/jwks, /lti/health, runtime and administration. Those routes belong to your provider deployment, not to the static P2LRN website.
Multi-institution security and isolation
- Cryptographically validate JWT and verify
iss,aud,azp,exp,iat,nonce,state, version, message type anddeployment_id. - Consume each transaction only once; prevent replay and access between institutions or deployments.
- Partition progress by institution, deployment, link, learner, attempt, package, review, and activity.
- Do not expose private keys, LMS credentials, personal data, or tokens within a
.p2lrnor browser URLs. - Refuse any access to unpublished content, non-existent activity or unauthorized service.
- Verify the results on the server before transmitting official notes.
Implemented teacher and learner flow
The administrator registers a platform and explicit deployments, catalog and bindings; unknown senders/deployments are rejected.
Deep Linking displays only published content and returns a signed resource linked to the review.
OIDC/JWT validates identity and deployment, creates a limited session and opens the same P2LRN Player.
The runtime persists state/events per session and attempt. A validated grade decision can be sent to AGS via the outbox.
This loop is covered by the provider's automated HTTP tests. Checking against each actual LMS must also be performed on the installation and version to be used.
Pre-deployment check
- Build Toolkit and Player, generate a persistent RSA key and deploy the server over HTTPS; do not expose the administrative token, private key, SQLite, or package directory.
- Register issuer, client ID, deployment ID, URLs and JWKS of the real LMS instance; find out
/lti/healthand/lti/jwks. - Publish a
.p2lrnreal in the catalog and verify Deep Linking or authorized manual binding. - Test teacher and learner: login, launch, Player, resume, expiration, replay, access denied and course copy.
- When there is AGS, check the column and note in the actual book. Do not declare NRPS or universal compatibility where it has not been tested.
- Repeat the matrix with questionnaires, 3D games, SCORM/H5P, mobile and cookie/iframe policies of the specific version of the LMS.
More information about the standard at 1EdTech LTI. For platform differences, consult Conectores LMS.