Skip to main content

4 posts tagged with "lti"

View All Tags

· 3 min read

When we started supporting LTI 1.3/Advantage (back in May of 2019) we chose to generate public/private key pairs for the tools. The tool vendor was then responsible for copying and storing those values on their side.

But the IMS Global community has moved away from that model and now suggests that tool vendors generate their own key pairs for LTI authentication and provide their public key via a JWKS URL.‚ÄĮThis model is more secure because there is not copying of a private key and allows the LTI Tool provider to follow best practices with key rotation.

We decided to follow that suggestion. If you want to register a new tool with Learn, you have to provide the JWKS URL information. And if you have an existing tool that use the Anthology-generated private key, please keep in mind that we'll be terminating support in the near future.

NOTE: Once you've made the change, you must have our mutual clients redeploy your LTI 1.3 tool. Redeploy means the following:

  1. Admin -> Integrations, LTI Tool Providers -> Register LTI 1.3/Advantage Tool
  2. Enter the same client ID for your tool that was previously deployed. Click the [Submit] Button.
  3. Your tool will be redeployed to use your new JWKS URL.

Follow the above steps exactly. Do NOT have them delete the integration as that will destroy all existing links to your tool, which can not be recovered.

Here is a video explanation of both the steps you need to take to update your tool's JWKS URL and the step you will need to have our mutual clients take. Note that after you update your tool's JWKS URL on the developer portal our mutual clients will NOT able to use your product until after they redeploy as described above and in the video.


  1. Is this just a background change, and it will not impact anything on the front end?
    -> There is no impact to how our mutual clients use the LTI Tool or Learn.
  2. Does making the change at the central location serve the purpose, or are we required to plan anything around individual connections for separate schools?
    -> You will need to work with the individual schools to ensure that after you make the chage they redploy your tool as described above.
  3. Will schools transition seamlessly once we transition from a static public key to keyset URL (JWKS), or does it require any intervention from the Black side or the school admins?
    -> The school admins will need to redeploy your tool as described above.
  4. Currently, both static public key and keyset URL (JWKS) are going through successfully. Is it because Anthology hasn’t yet discontinued supporting the static public key?
    -> Anthology will continue supporting the keys that were originally provided until further notice, likely until the end of 2022*.

As always, if you have any questions, check out the contact us page and let us know!

*Statements regarding our product development initiatives, including new products and future product upgrades, updates or enhancements represent our current intentions, but may be modified, delayed or abandoned without prior notice and there is no assurance that such offering, upgrades, updates or functionality will become available unless and until they have been made generally available to our customers.

· 5 min read

In testing with the Google Canary Chrome Browser, one of our clients discovered an issue that was blocking users from logging in to their Learn instance. After much troubleshooting, we discovered a multi-layer issue that brings us to, you guessed it, cookies.

This affects clients in SaaS with Ultra Base Navigation enabled using Ultra integrations that rely on UEF

Here is a brief description of the contributing factors:

First, the client had built a custom Ultra login page. The page included code designed to ensure that Learn login pages would never render inside of an iframe within Learn. It looks like this:

if ( top != self )
    top.location.replace( self.location.href );

In and of itself there's nothing wrong with it. We, at Anthology, have removed it from the default Ultra login page, but many clients use it in Original login pages, and so it's moved with them into Ultra.

If you are unsure whether you have a custom login page, visit for more information.

Secondly, when a user logged in, Ultra Extensions automatically fired off an LTI launch to UEF-enabled tools. The way UEF works is: after the LTI launch is validated, the tool redirects to the Learn REST endpoint to initiate a UserAuth flow. In our documentation, we call this a Three-Legged OAuth or 3LO. In most cases, it's a process that relies on a session cookie to hold everything together. This impending release of Chrome (and other browsers) will block this cookie because everything is happening across domains and involves the use of iframes.

So what happens is that, even though the integration is configured in Learn to not force the end-user to authorize the integration, the lack of the session cookie means that Learn has no idea that this user is logged in, so it pops open the login page.

Remember that code snippet above in the custom login page? Well, that takes over the entire browser page with the Learn login. And when the user logs in again, it renders the JavaScript meant for the UEF iframe into the page. In other words, it overtakes your Learn browser session. There is no way to actually get past that screen.

Related, this same issue affects Safari users when cross-site tracking is disabled.

So what can you do?‚Äč

Well, that depends upon who is reading this blog. If you are an administrator trying to get your users back in Learn, the most immediate fix is to remove that snippet from your login page. It won't fix your broken UEF integration, but it will at least let your users log in and interact with Learn.

If you are a developer that has built a UEF integration, we actually implemented a fix for this in April: a way to bypass the need for a session cookie in this process. In the LTI launch, we now provide what is called a one-time session cookie. This is present in both LTI 1.1 and 1.3 launches.

If you are using LTI 1.3, there's a small bug in this. I will share a workaround that will both get around this bug, but not fail when the bug is fixed.

This one-time session cookie is added to the claims in the LTI 1.3 JWT and the form POST parameters in LTI 1.1. You can grab that value from the LTI launch, return it as a parameter in your 3LO authorization code request, and your problem will be solved.


In LTI 1.3, you will see the value in the claim. This token is made up of a specially generated token value. It should also be followed by a comma and the user's UUID. The bug is that the comma is missing. Luckily, the user's UUID is the sub token in the same set of LTI claims. We intend to fix this, but to ensure your code works both now and after the fix, you can simply look for the comma. If it's not there, append it and the sub and you will be off and running. Here's a Python 3 code snippet to illustrate how this might look. We will be updating our UEF sample code, but at the time of this writing, we have not done so.

    # Get the value of the one time session token from the LTI claim
    one_time_session_token  = message_launch_data['']

    # If there is no comma in the value, we've hit the bug. Add it and the user's UUID
    if "," not in one_time_session_token:
        one_time_session_token += "," + message_launch_data['sub']

    # Add the one_time_session_token to the query parameters to send to the Authorization Code endpoint
    params = {
        'redirect_uri' : Config.config['app_url'] + '/authcode/',
        'response_type' : 'code',
        'client_id' : Config.config['learn_rest_key'],
        'one_time_session_token' : one_time_session_token,
        'scope' : '*',
        'state' : str(uuid.uuid4())

    # Encode the parameters
    encoded_params = urllib.parse.urlencode(params)

    # Redirect the successful LTI validation to the Authorization Code endpoint
    return(redirect(learn_url + '/learn/api/public/v1/oauth2/authorizationCode?' + encoded_params))


By now, I hope you are using LTI 1.3, but I know many are not. As a result, we also added a one-time session token to LTI 1.1 launches. This will come in the form POST parameter ext_one_time_session_token. Just like in the 1.3 example, your application should take this value from the LTI launch, append it to the authorization code request endpoint as one_time_session_token=that_token and redirect them to the authorization code endpoint.


We have validated this fix with one of the partners that was affected. If you are a developer, please fix the issue immediately! If you are an administrator of a Learn SaaS instance using Ultra, and you have UEF integrations, make sure you do not have that JavaScript snippet on your login page. And if you do, please remove it. Then let your UEF integration partners and developers know that this fix must be made as soon as possible.

Regardless of whether you are an administrator or a developer, please feel free to reach out to us at with any questions.

Happy coding!

· 2 min read

Most people like cookies. Internet browsers used to like cookies, but a lot has changed in the last few years.

We are seeing a lot of applications stop working in some browsers because cookies are not being shared, and this post hopes to help explain why that is happening and what can be done about it.

A web application may set a cookie to track a user‚Äôs session. This is very common, however if your web application is going to be hosted in an iframe, then there‚Äôs a good chance your cookie won‚Äôt be sent back to you. This is because browsers are clamping down on sending ‚Äú3rd-party‚ÄĚ cookies back to applications hosted in an iframe. Note that a 3rd party is a site that is hosted on a domain different than the 1st party, or your web application. The reason is because these cookies can be used for tracking your internet and browsing activity. Safari has disallowed this for years as a user privacy measure.

Another case where cookies aren’t being sent back is during a form POST back to your application. If you set a cookie, then launch to a 3rd party application, if that application does a form POST back to you, the browser will likely not send your cookie back because it is trying to help prevent cross-site request forgery attacks.

Rather than detail all the scenarios and work arounds here I link to two web pages that are immensely helpful in explaining the situation and some possible workarounds.

The TL;DR is if you must set a cookie in your web application, be careful how you configure that cookie’s properties, and understand that at least in Safari, your cookies may not get passed back to you. The other browser makers are going to get as restrictive as Safari soon.