To Our Amazing Educators Everywhere,
Happy Teacher Appreciation Week!
Found this content helpful? Log in or sign up to leave a like!
So my tool creates bits of user generated content, and it is very handy to be able to provide a url that links directly to one of those pieces of content. However I can't passes any arguments to the external tool definition that canvas uses to perform the basic lti launch
I want to be able to do something like this
https://canvas/courses/14/external_tools/25?link=/deep/content/link => https://my.tool.url/lti?link=/deep/content/link
I understand that canvas does not currently repackage GET params, from the launch link back into the basic_lti_launch, however I am looking for a solution that can achieve this same effect.
Is there any other way to accomplish this, where I can pass arbitrary url parameters thru to the external tool launch?
Clarification:
This needs to be a solution that doesn't require any admin rights, i.e. a student can generate the url for sharing etc..
Solved! Go to Solution.
Here is the workaround that I ultimately settled upon .. and it is working well.
I created a page inside my application that acts as a redirector (lets call it deeplink); the code flow works like this
I'm not an expert with the external tools (I hate them, actually), but I believe I've worked with them enough to be able to answer this (just take it with a grain of salt).
When you configure the "External App", you have to supply a Launch URL. You could add it directly to this. We have to do this for integration of Bookshelf Online and Chalk & Wire Learning Assessment. So, assuming "https://my.tool.url/lti" is your current Launch URL, simply add to the end of it that additional string you want to use. This would also help you to avoid in issues with regards to their new policy of allowing only one Launch URL per access path, assuming you need to load multiple links with a different additional field.
For multiple links off the same base Launch URL, you could alternatively leave the Launch URL as "https://my.tool.url/lti" and add the additional portion to wherever it is linked. This'll allow you to have the single "External App" while using different additional GET parameters. This is the solution we use for the two scenarios I mentioned, and it's worked fairly well, despite the subtle changes Instructure has made over the last year that seems to be targeted at ending use of multiple external tools from the same source.
Thanks for the reply, unfortunately I need to use something similar to #2 where I can create the urls more dynamically, however I need to be able to pass a launch url that I can trigger from outside canvas, so that it will pass thru the canvas SSO flow.
The problem is I when I append params onto the courses/{id}/external_tools/{id}?myparam=test and canvas converts that url into an LTI launch with post params, it does not append the additional GET params into the launch post.
Where exactly are you putting the change at? There shouldn't be any point where you're appending it to the end of a Canvas-generated URL.
Here's what I'm referring to with that second scenario:
The Launch URL of the "External App" is "https://epcs.chalkandwire.com/epcs/lti/tool", as shown above. The problem is that we load this external tool multiple times into a course, targeting a different point. To do this, every time that tool is selected, the URL is modified to point to the intended target:
The "External App" is a single configuration, but by modifying the URL where it is used, we use the desired configuration with the desired destination.
At no point is there a modification to a Canvas-generated URL. "/courses/1234/modules/items/12345678" remains unchanged, but it's destination goes to where we wanted it to.
With regards to the GET vs POST, I did say I'm not an expert with external tools, so what is entered as a GET in the configuration may be converted to a POST, though that wouldn't make any sense to me.
I understand that I *shouldn't* be appending to the canvas generated url, however that is the very effect that I am trying to achieve, and modifying the launch configs is not an option (I would have to generate 10000s of launch configs for each course). There ought to be a way to create a deep link to content contained inside a LTI application where you can create a specific reference to it in a canvas wiki page, or in a discussion in such a way that when I click on the wiki link it
1) Launches the LTI application
2) Passes some addtl deep link parameter into the lti application so the app can forward you to a specific piece of content.
With what I described, you only have one "External App" configuration. Here's a short video I just made to demonstrate this: http://www.screencast.com/t/NxEe9MCmxAn
Again, I fully understand that, but you are missing my key point.
Imagine a scenario where a student uses an LTI tool to author a piece of content, and then wants to send a link to that content to another student/teacher etc.. the most natural way to do this would be via a link. However you cannot generate a link to a backend lti tool, because you won't be passing thru the canvas SSO process and the backend LTI tool will have no context as to who you are.
This is why I am asking if there is a way to generate links that passes parameters thru the canvas side of the link [thus making them stable, and able to be sent to people who might not have an active sign-in cookie] to the backend lti application.
Ah, you didn't mention it was for use by students. Teachers could just use the process I provided and provide the module link, but student cannot. That's the key difference between what I was demonstrating and what you wanted but didn't mention.
Alright, in that case it is not possible through the external tool. You'd have to make a non-LTI access method to allow this. Modifying a Canvas URL requires Canvas to process that additional data. Any changes not strictly covered by the LMS will be ignored. Any changes covered by the LMS will be handled by Canvas as it sees fit.
Simply put, you should avoid trying the modify "/courses/:course_id/external_tools/:id" to provide your parameters and seek an alternate solution.
VitalSource has a similar issue with its deeplinking. They support deeplinking via a standard anchor, but the user must be authenticated. With an external tool, authentication is automatically done, but a basic hyperlink won't do this. The only solution to making these work for VitalSource (since we're limited to one configuration per Launch URL and deeplinking via LTI requires Custom Parameters) is to instruction the user (student or teacher) to access the LTI if accessing a deeplink doesn't work, then try the deeplink, again.
You'd need a similar process to make something work that would be manipulable by students.
Since apparently it's not possible to have Canvas do it for you, see if you can create a "sharable string". When a user decides to share something, instead of generating a deep link, create something like "aardvark316" or whatever (which is mapped to however you store the necessary state).
Another user can then type that code in to see (and hopefully bookmark somehow) the relevant content.
It is a bit of a kludge, but if you do your UX right, you might be alright.
To make it possible to actually make a deep link, I believe you might need to change the code around here to append any params to the URL. I don't know where that data would come from, since I'm not really familiar with Canvas' inner workings.
I'm not very experienced with Ruby (Canvas is my first real working with the language), so I didn't want to go into the code to supply and answer when I wouldn't be sure of its accuracy. Further, it doesn't do much good for those using Instructure-hosted instances as we're unable to modify the code.
The suggestion of a short url feature is good, but that also adds a requirement to store the short url identifier and it's target destination. If there's already a dynamic data storage method in place on the target system, which is most likely so since the target is an external tool system, this would be a minor thing to accommodate. It, however, the external tool system is actually a static data system the only authenticates access, this could prove more difficult since such a system wouldn't actually require dynamic data storage.
In all, I think it's brilliant, but I wanted to clarify it's requirements.
Christopher Esbrandt wrote:
I'm not very experienced with Ruby (Canvas is my first real working with the language), so I didn't want to go into the code to supply and answer when I wouldn't be sure of its accuracy. Further, it doesn't do much good for those using Instructure-hosted instances as we're unable to modify the code.
It was more of a suggestion for someone who did have more experience to submit it as a patch.
The suggestion of a short url feature is good, but that also adds a requirement to store the short url identifier and it's target destination. If there's already a dynamic data storage method in place on the target system, which is most likely so since the target is an external tool system, this would be a minor thing to accommodate. It, however, the external tool system is actually a static data system the only authenticates access, this could prove more difficult since such a system wouldn't actually require dynamic data storage.
In all, I think it's brilliant, but I wanted to clarify it's requirements.
Glad you think so 🙂
Creating such a system is trivial: you only need a table with two columns (short_thing, actual_link) and a very short script (~10 lines of PHP if you wanted to go that route).
@peter3 says:
"However you cannot generate a link to a backend lti tool, because you won't be passing thru the canvas SSO process and the backend LTI tool will have no context as to who you are."
If the student is creating content inside your environment, and if you have specific sharing rules, would it make sense to manage content, sharing and associated rules from within your environment?
Have you considered providing a "dashboard" view in your app, which would include a list of shared content from within your app?
In other words, allow the student to access your app as a dashboard instead of an assignment. From the dashboard you can display both a list of assignments, and display a list of content that has been shared with them. You also now have control over how content is shared, and you are leveraging authentication.
ebook vendors use a similar approach: one entry point allowing students to find reading material as well as assignments enabled by the instructor. You might also need to provide an instructor dashboard, allowing the creation of assignments from your environment.
This approach adheres to the SSO issue you mention, and requires no special privs in Canvas. It also allows you to implement any proprietary business logic necessary to meet your requirements.
Just trying to brainstorm.
Here is the workaround that I ultimately settled upon .. and it is working well.
I created a page inside my application that acts as a redirector (lets call it deeplink); the code flow works like this
That's great, but it requires modifying the code, right? This is something that instructure-hosted customers can't really do.
Nope, it does not you to modify the code, and I have tested it with hosted it works just fine, you are just installing a different LTI app into the site that is hidden and serves as a redirector, similar to an openid auth flow.
This is a bit of a hackish solution. Don't get me wrong, it works, but its far from ideal. The user leaves Canvas via a standard HTTP(S) request, which then creates a cookie and redirects the user back to Canvas to access the external tool, which then uses the cookie to send the user to the desired location. It's, with my limited understanding on network security, a security nightmare.
Having said that, it's an inspired solution that avoids the need to modify any Canvas code. However, I have to ask: how is your redirect/cookie-generating page determining the URL of the external tool to redirect to? If it's going off the referrer information, then you're going to have an issue with Internet Explorer (all versions) and applying these links in the modules list. Canvas opens external URLs in a new tab via JavaScript, which blocks referred data in the browser. It's a flaw Microsoft finally address in Edge, but that browser is filled with all sorts of other issues.
Security isn't bad, b/c the link reflector doesn't do anything, and when it comes back the user is already full authenticated .. plus I am assuming that your backend application enforces the roles in accordance with the launch params.
You don't use the referrer information (that would be bad), you can either hard code it on the back end because the reflector lti endpoint url is stable across all courses/placements and doesn't change. Or you can look it up using the canvas rest API External Tools - Canvas LMS REST API Documentation
Also to be clear, put it in a cookie, or stuff it in a session .. 6of1halfdozentheother. It should be known that this is how a ton of sites funnel you through their login screen .. including .. canvas
Alright, then does it work for people that don't have permission to access the point where the external tool is linked? If so, how'd you manage that? A user without permissions for an account or course will be unable to access practically anything from them.
Basically, a user not enrolled in course 42 cannot access content from course 42, unless they have higher permissions, like administrators.
Further, just testing accessing an external tool direct with administrative rights then normal student (enrolled) rights, I got the error:
Couldn't find valid settings for this tool
That's from accessing "/courses/:course_id/external_tools/:external_tool_id" directly. How'd you work around that? I got it for external tools with and without custom fields.
For a non-enrolled student account, I got the standard Unauthorized error.
Okay, but this is all really complicated.
Ideally, it would work out of the box, with no special configurations or hidden LTI links. I mentioned the relevant part of the code you'd need to change above, for someone who can program in Ruby. Maybe someone who understands the LTI specs can put in a feature request so it's done properly.
I agree it would, but if it did .. I wouldn't have had to ask the community for work arounds..
also it's not that complicated, and doesn't require ruby .. it's 10 lines of java code .. probably 6 in php.
To participate in the Instructure Community, you need to sign up or log in:
Sign In