Ad-hoc platforms for LTI tool integrations testing

Definitions and References for this post

The search for up-to-date tool provider examples written in Python

In attempting to learn more about how I could leverage Python Flask or Django in developing a new LTI tool provider, I discovered some excellent (and up-to-date, as of this post) examples that I could use to build something locally for testing, and that I’m able to run fairly easily. This search wasn’t super-easy since there isn’t a lot that takes into account the newer standards with LTI 1.3 / Advantage, and isn’t dated like MITs pyLTI with support only for LTI 1.1 and/or 2.0 standards.

Dall-E generated: “oil painting of three dimensional bridge connecting two computers with a night sky background”

Finding a platform for testing an LTI

With the newer GitHub example project, I was able to build a local development environment, start up a Flask server, and serve up a simple tool that could be tested. BUT, I need a platform to do the proper testing! Launching endpoints will just error out until I have the context in place, within a course, in an LMS… or at least a simulated version of an LMS. That’s where saLTIre came in handy for this purpose. Let’s a take a look at how to properly set up this Flask example by making some changes to the tool provider’s configuration in order to get it to work properly with saLTIre platform emulator.

Setting up the Flask app for use with saLTIre

Step 1 – Set up your development environment and clone the repo

If you know how to deploy a Docker container to your desktop, that’s probably the easier method, outlined here: https://github.com/dmitry-viskov/pylti1.3-flask-example. I personally prefer getting things set up locally in a Python virtual environment, so that’s the option I used.

$ cd ~/dev
$ git clone git@github.com:dmitry-viskov/pylti1.3-flask-example.git
$ python -m venv ~/dev/python_envs/flask_lti13
$ source ~/dev/python_envs/flask_lti13/Scripts/activate
$ cd ~/dev/plylti1.3-flask-example
$ pip install -r requirements.txt
$ cd game
$ python app.py

The above is copied from the bottom of the GitHub repo’s README for this project, with a couple of minor changes for my personal environment. I’m using Git-Bash for Windows for this one and I like to store all my Python virtual environments in one directory, embedded in my development environment. I already have a dev directory in my home directory that contains all my various tests and projects.

Really, it’s up to you!

Please refer to Real Python’s primer for doing this properly in your choice of virtual environment.

Running python app.py will run the server… and if there are no errors to address, go ahead and shut it down before completing the next steps (Ctrl+C).

Step 2 – Add a new configuration that works with saLTIre

One thing you’ll notice with this project is that it includes several configurations in /configs/game.json for major Learning Management Systems like Canvas, Blackboard, Moodle, and D2L. It also includes additional client configurations for 1EdTech’s platform emulator / reference implementation and validator.

Since there wasn’t one for saLTIre, I added the following to the bottom of the file. It looks something like this:

"https://saltire.lti.app/platform": [{
        "default": true,
        "client_id": "saltire.lti.app",
        "auth_login_url": "https://saltire.lti.app/platform/auth",
        "auth_token_url": "https://saltire.lti.app/platform/token/1026212c6ba048ba418392ef4c51013d",
        "key_set_url": "https://saltire.lti.app/platform/jwks/1026212c6ba048ba418392ef4c51013d",
        "key_set": null,
        "private_key_file": "private.key",
        "public_key_file": "public.key",
        "deployment_ids": ["cLWwj9cbmkSrCNsckEFBmA"]
}]

Where did I get most of these parameters from? I’ll show you in the next step. We’ll get them from the saLTIre platform emulator. Go ahead and save the new platform config to the game.json file. You can adjust anything you need in here once the next steps are complete.

Setting Up saLTIre

Step 1 – Create an account

Go to https://saltire.lti.app/platform and create an account. This may not be necessary but it allows you to save some of your tool-level configurations for subsequent use. You must have a Google account in order to sign in.

Click the Options dropdown -> Sign in

Step 2 – Configure the Security Model

Select Security Model and configure the following:

  • LTI version -> 1.3
  • Message URL -> http://127.0.0.1:9001/launch/
    • Use the tool’s launch URL for this. If you followed the Flask app setup above (along with the github readme, you should be working with localhost and TCP port 9001.
  • Ensure that the signature method is set to -> RS256 (JWT Authorization).

Step 3 – Enter the LTI Tool Details

Whilst you are still on the Security Model page:

  • Initiate login URL -> http://127.0.0.1:9001/login/
  • Redirection URI(s) -> http://127.0.0.1:9001/launch/
  • Public key -> This (full text) needs to be copied from the key included with your Flask tool implementation. You can grab that from here (assuming your paths are like mine): ~/dev/plylti1.3-flask-example/configs/public.key. Essentially, the public key that you’ll want is inside your projects root directory -> configs, where we also found the game.json file.

After this is complete, you can register the tool, make it public and save your config. This is purely up to you but is great for future reference.

Click Save at the top of the screen, next to the saLTIre logo.

Step 4 – Confirm/configure platform details in the tool configuration

Yes, you are still on the Security Model page…

You’ll want to ensure that the /config/game.json contains the following platform details for the saltire platform configuration.

  • Client ID -> client_id
  • Deployment ID -> deployment_ids
  • Application Request URL -> auth_login_url
  • Access Token service URL -> auth_token_url
  • Public keyset URL -> key_set_url

Save the changes to the game.json file.

Step 5 – Configure the Message Type in saLTIre

Select the Message from the left navigation. At this point you will have different results based on the type of app you are using. With the game that we’re trying to launch, either deep linking or resource link requests will work, but each with different results. You will want to use the Deep Linking request in order to complete a full test and get back a response.

In this example, I’m selecting LtiDeepLinkingRequest

Once Deep Linking is selected, you’ll be presented with more options. Feel free to play around with this once things are up and running to gauge what the various results will be based on certain selections.

  • Beyond the defaults, at least LtiResourceLink needs to be added to the list of accepted types.
  • Don’t forget to click SAVE at the top of the page.

Launch the App locally and connect!

Launch the app.py in your <app root>/game directory. Don’t forget to enable the virtual environment. Should look something like this (I’m using git-bash on Windows):

source ~/dev/python_envs/flask_lti13/Scripts/activate
cd ~/dev/flask_projects/pylti1.3-flask-example/game
python app.py

If all is well and without errors, try launching into the LTI tool from the platform by clicking on Connect at the top right corner of the screen. You can also select some options from the Connect drop-down for various launch conditions. One excellent way to debug the connection payload is to use the Preview connection option — one of my favorite items.

Once Launched the tool should present a difficulty selection…

… and with the deep linking option in saLTIre, you won’t get an opportunity to play the game but you’ll return to the platform with a whole lot of info and a verification status. You should see a green Passed if all went well.

You are able to play the game if you change the message type from LtiDeepLinkingRequest to LtiResourceLinkRequest. You can also see the name of the student in the game.

A score is likely being passed back… but that’s where I wasn’t able to make it ALL happen inside of saLTIre. I can certainly get us to an end, but would love to see this workflow work properly.

Launch and Authenticate -> Select Difficulty -> Play game to completion and close -> Score is passed back to the “gradebook” and a column created.

I’m hoping it’s just something I missed in the config but would be happy to hear what you think and if anyone out there can help me craft a solution. This is a great example of a working app inside of an LMS platform with score pass-back as a potential option.

Thanks! I’m looking forward to your feedback. Follow-ups and upcoming posts will include:

  • An explanation of what all this is and an exploration of authentication in LTI 1.3.
  • Trying out the Django version of this example in saLTIre.
  • More closely checking out the tool inside the 1EdTech platform emulator. I attempted this option prior to using saLTIre and was disappointed in the results and received several errors. Perhaps saLTIre is just forgiving? Not sure.
  • Building an LTI app using Python and potentially exploring lowcode / nocode tools for implementing an LTI. What are the security challenges(?), etc.

Leave a Reply

Your email address will not be published. Required fields are marked *

53 + = 56

This site uses Akismet to reduce spam. Learn how your comment data is processed.