canvas_lti_third_party_cookies
Safari blocks all 3rd-party cookies by default, which breaks LTI tools that rely on setting cookies when launched in an iframe. Other browsers will soon follow suit. Instead, Safari exposes a new API for getting user-permitted access to set cookies from an iframe, which unfortunately doesn't completely work for LTI use cases.
See this article for a detailed explanation of the Storage Access API and previous attempts to launch LTI tools in Safari: https://community.canvaslms.com/t5/Developers-Group/Safari-13-1-and-LTI-Integration/ba-p/273051
The current workaround that this gem implements is to relaunch the tool in a new tab, new window, or popup window, where it can set first-party cookies to its heart's content. The relaunch occurs during the login request, so the tool is entirely in control, and no other parts of the LTI launch flow are modified.
Installation
Add this line to your application's Gemfile:
gem 'canvas_lti_third_party_cookies'
And then execute:
$ bundle install
Since this gem includes some static assets (JS, CSS, images), you will need to make sure
that your application runs the rake assets:precompile
task at some point during its
build process. Most Rails applications will be running that already, either directly or
as part of the rake webpacker:compile
task.
Neglecting to precompile assets will result in runtime errors when users try to launch
your LTI tool.
Usage
Choose the Rails controller action that's used to handle tool authentication requests.
Set the before_action callback below to run on that action, and pass the data needed.
redirect_url
(required): the authorization redirect URL to continue the login flowredirect_data
(required): all form data required for the authorization redirect, which
the previous login render call should have included in a form tag.window_type
: (optional) Set to :new_window
to open the tool in a
new tab or window, or to :popup
to open in a popup window.
Defaults to :new_window
.width
: (optional) The width the popup window should be, in px. User
has the discretion to ignore this. Only valid with window_type: popup.
Defaults to 800px.height
: (optional) The height the popup window should be, in px. User
has the discretion to ignore this. Only valid with window_type: popup.
Defaults to 600px.
example:
include CanvasLtiThirdPartyCookies::RelaunchOnLogin
...
def login
state, nonce = create_and_cache_state
redirect_url = 'http://canvas.instructure.com/api/lti/authorize_redirect'
redirect_data = {
scope: 'openid',
response_type: 'id_token',
response_mode: 'form_post',
prompt: 'none',
redirect_uri: tool_launch_url,
client_id: params.require(:client_id),
login_hint: params.require(:login_hint),
lti_message_hint: params.require(:lti_message_hint),
state: state,
nonce: nonce
}
relaunch_on_login(redirect_url, redirect_data)
end
Local Development
To make changes and test them locally, it's possible to install this gem in a local
LTI tool installation.
- In your tool's Gemfile, add
, path: './cookies'
to the line for this gem. - In your tool's docker-compose.override.yml, add a new volume to link this gem's
folder to the
./cookies
path. It should look like this:
volumes:
- ./path/to/lti_third_party_cookies:/usr/src/app/cookies
bundle install
again.
The same process is possible with non-docker-compose apps, just directly point to the
gem's folder from your tool's Gemfile.
Testing
Ruby Tests
The ruby tests use minitest
, which comes bundled with rails. To run them locally:
rails test
There is a Docker setup for running tests that's used for CI. To run them in Docker locally:
docker build -f test/Dockerfile.ruby -t ruby-test .
docker run --rm ruby-test rails test
Javascript Tests
The JS tests are self-contained in the test/javascripts
folder. To run them locally:
cd test/javascripts
yarn install
yarn test
There is a Docker setup for running tests that's used for CI. To run them in Docker locally:
docker build -f test/Dockerfile.node -t node-test .
docker run --rm node-test yarn test
i18n
All user-facing strings in this gem are localized and translated into the languages that
Canvas supports. Any time that any strings are changed, you should make sure this is run:
rake app:i18nliner:dump
Then, add config/locales/generated/en.yml
to your commit.
After making changes to en.yml
, you will need to push these changes to the
instructure-translations
S3 bucket so that the translators can update other locales.
TODO: the script or Jenkins job to actually push to S3.
Once translators have finished updating other locales, they will notify you, and you can
pull down the new locale files into config/locales
, and commit and push them.
TODO: the script or Jenkins job to pull from S3.
Publishing New Versions
- Bump the version in
lib/canvas_lti_third_party_cookies/version.rb
. rake install
- Commit, push, and merge that change.
gem push pkg/canvas_lti_third_party_cookies-<version>.gem
- note that this will only work if you have access