A local development platform for testing LTI 1.1 tool integrations. Built with Python, FastAPI, and SQLite3.
Part of the LAMB Project - an open source project developed by Marc Alier and Juanan Pereira, professors and researchers at the Universitat Politècnica de Catalunya (UPC) and Universidad del País Vasco (UPV/EHU).
- Tool Server Management: Add and manage LTI tool server configurations (domain + port)
- Tool Configuration: Configure tools with consumer key/secret, launch paths, and custom parameters
- Demo Courses: Pre-seeded courses with 2 teachers and 4 students each
- User Switching: Easily switch between users to test different roles (Instructor/Learner)
- Flexible Launch: Launch tools in iframe or new tab
- Launch Inspection: View all launch parameters, signed requests, and OAuth signatures
- Grade Reception: Receive grades via LTI Basic Outcomes Service (replaceResult)
- Complete Logging: Full audit trail of all launches and grade submissions
# Install dependencies
pip install -r requirements.txt
# Run the platform (port 8000)
python app.py
# In another terminal, run the sample tool (port 8080)
python sample_tool.py# Build and run the platform
docker build -t lti-platform .
docker run -p 8000:8000 lti-platform
# Or use docker-compose
docker-compose upWhen running in Docker, use host.docker.internal instead of localhost to access services on your host machine.
Navigate to Tool Servers and add your LTI tool's server:
- Name: A friendly name for the server
- Domain:
localhost(orhost.docker.internalin Docker) - Port: The port your LTI tool runs on (e.g.,
8080)
Navigate to Tools and create a new tool:
- Tool Server: Select the server you just created
- Launch Path: The LTI launch endpoint (e.g.,
/lti/launch) - Consumer Key: Your OAuth consumer key
- Consumer Secret: Your OAuth consumer secret
- Custom Parameters: Optional JSON object for custom LTI parameters
Navigate to Courses, select a course, and add your tool to it. This creates a unique resource_link_id for the course-tool combination.
- Select a user (teacher or student) from the user cards
- Click Launch (iframe) or Launch (new tab)
- The platform will:
- Build all required LTI 1.1 parameters
- Sign the request with OAuth 1.0a HMAC-SHA1
- Submit the form to your tool
- Log the complete launch for inspection
Navigate to Launch Logs to see all launches. Click Inspect to view:
- All unsigned parameters
- Complete signed request
- OAuth signature details
- User and context information
When your tool sends grades back, they appear in Grades. The platform provides:
- Score display (as percentage)
- User and course context
- Raw XML payload for debugging
The platform sends all standard LTI 1.1 parameters:
lti_message_type: basic-lti-launch-requestlti_version: LTI-1p0
oauth_consumer_keyoauth_signature_method: HMAC-SHA1oauth_timestampoauth_nonceoauth_version: 1.0oauth_signature
context_idcontext_labelcontext_titlecontext_type: CourseSection
user_idlis_person_name_givenlis_person_name_familylis_person_name_fulllis_person_contact_email_primaryroles: Instructor or Learner
resource_link_idresource_link_title
lis_outcome_service_urllis_result_sourcedid
tool_consumer_instance_guidtool_consumer_instance_nametool_consumer_info_product_family_codetool_consumer_info_version
The included sample_tool.py is a complete LTI 1.1 Tool Provider that:
- Validates LTI launch requests
- Verifies OAuth signatures
- Displays launch context and parameters
- Sends grades back to the platform
Run it on port 8080:
python sample_tool.pyDefault credentials:
- Consumer Key:
test_key - Consumer Secret:
test_secret
Your LTI tool should send grades to:
POST http://localhost:8000/outcomes
Example replaceResult XML:
<?xml version="1.0" encoding="UTF-8"?>
<imsx_POXEnvelopeRequest xmlns="http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
<imsx_POXHeader>
<imsx_POXRequestHeaderInfo>
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>unique-id</imsx_messageIdentifier>
</imsx_POXRequestHeaderInfo>
</imsx_POXHeader>
<imsx_POXBody>
<replaceResultRequest>
<resultRecord>
<sourcedGUID>
<sourcedId>{lis_result_sourcedid}</sourcedId>
</sourcedGUID>
<result>
<resultScore>
<language>en</language>
<textString>0.85</textString>
</resultScore>
</result>
</resultRecord>
</replaceResultRequest>
</imsx_POXBody>
</imsx_POXEnvelopeRequest>When your LTI tool runs in a Docker container and needs to send grades back:
- Platform → Tool: Use
host.docker.internal:8080as the tool domain - Tool → Platform: The outcomes URL will be
http://host.docker.internal:8000/outcomes
Or use the provided docker-compose.yml with a shared network.
The platform auto-seeds with:
- CS101 - Introduction to Python
- WEB201 - Web Development
- DS301 - Data Science Fundamentals
- Dr. Alice Smith (alice.smith@example.edu)
- Prof. Bob Johnson (bob.johnson@example.edu)
- Charlie Brown (charlie.brown@example.edu)
- Diana Prince (diana.prince@example.edu)
- Edward Norton (edward.norton@example.edu)
- Fiona Green (fiona.green@example.edu)
All users are enrolled in all courses.
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Dashboard |
/tool-servers |
GET | List tool servers |
/tool-servers/add |
POST | Add tool server |
/tools |
GET | List tools |
/tools/add |
POST | Add tool |
/courses |
GET | List courses |
/courses/{id} |
GET | View course |
/courses/{id}/tools/add |
POST | Add tool to course |
/launch/{course_tool_id} |
GET | Launch tool |
/launch-logs |
GET | List launch logs |
/launch-logs/{id} |
GET | View launch log |
/grades |
GET | List grades |
/grades/{id} |
GET | View grade |
/outcomes |
POST | Receive grade (LTI Outcomes) |
- Backend: FastAPI (Python)
- Database: SQLite3
- Styling: Embedded CSS (no external dependencies)
- OAuth: Custom HMAC-SHA1 implementation
GPL v3.0