cancel
Showing results for 
Search instead for 
Did you mean: 
trip_gould
Community Member

404 Error on LTI launch for local running test app

Jump to solution

I am developing an external tool for Canvas integration.  The app and all of its endpoints function properly when running in a browser tab, but when launched from the Canvas editor button I have created for my LTI placement, the route returns a 404 error and a message in the launched modal UI stating "Cannot POST /lti_launch".  I have tried setting up multiple routes just to see and they all end up with "Cannot POST /<my route here>".

I have made sure that etc/hosts has been edited to point 127.0.0.1 to my domain -- in this case the format is:

127.0.0.1 canvas.myapp.com 

-- and that DNS setup does work when outside of the Canvas LTI launch modal in a standard browser tab.

My XML is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0"
xmlns:blti = "http://www.imsglobal.org/xsd/imsbasiclti_v1p0"
xmlns:lticm ="http://www.imsglobal.org/xsd/imslticm_v1p0"
xmlns:lticp ="http://www.imsglobal.org/xsd/imslticp_v1p0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd
http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0.xsd
http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd
http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">
<blti:title>KUP16</blti:title>
<blti:description>Plugin Test 16</blti:description>
<blti:icon></blti:icon>
<blti:launch_url>https://canvas.myapp.com:8080/lti_launch</blti:launch_url>
<blti:extensions platform="canvas.instructure.com">
<lticm:property name="tool_id">knowbly_plugin_16</lticm:property>
<lticm:property name="privacy_level">public</lticm:property>
<lticm:property name="domain">canvas.myapp.com</lticm:property>
<lticm:options name="editor_button">
<lticm:property name="url">https://canvas.myapp.com:8080/lti_launch</lticm:property>
<lticm:property name="text">Plugin Test 16</lticm:property>
<lticm:property name="selection_width">500</lticm:property>
<lticm:property name="selection_height">400</lticm:property>
<lticm:property name="enabled">true</lticm:property>
</lticm:options>
</blti:extensions>
<cartridge_bundle identifierref="BLTI001_Bundle"/>
<cartridge_icon identifierref="BLTI001_Icon"/>
</cartridge_basiclti_link>

That was generated using the tool at XML Config Builder 

The Network tab info looks fine:

Request URL:
Request Method:

POST
Status Code:

404 Not Found
Remote Address:

127.0.0.1:8080
Referrer Policy:

no-referrer-when-downgrade
Except, of course, for the 404 Not Found error.  But the Request URL is correct and the Remote Address is correct.  The Form Data being passed looks good, as well, with all of the expected LTI data that I would hope to capture.
So, it really just comes down to that 404 terminating the communication before it reaches the route it thinks does not exist.  Any thoughts?  Any more info I can provide?
Thanks.
Tags (1)
1 Solution

Accepted Solutions
trip_gould
Community Member

I figured out how to set up an endpoint on the GraphQL server using Express middleware, so that was all that was needed for receiving requests in this setup.  Now I just have to figure out how to get the apollo-graphql server to run over https://

View solution in original post

7 Replies
stuart_ryan
Community Coach
Community Coach

Hi  @trip_gould ,

I will admit I have never done any LTI development myself, so this is something that would benefit from the experience of some great minds that have. With that in mind I will share this with the Canvas Developers‌ group.

One thing that did come to mind though, is you could use something like Fiddler Fiddler - Free Web Debugging Proxy - Telerik to proxy the traffic locally on your machine (including intercepting the HTTPS traffic, which I strongly recommend you remove after you have used it to prevent man in the middle attacks). Dynatrace has a good quickstart guide on this How do I use Fiddler to capture HTTP/HTTPS sessions for debugging? | Dynatrace Help 

Using Fiddler, you should be able to see exactly what HTTP/S requests are sent, received, and with all the headers attached, and can hopefully lead you to narrowing down the problem.

Hope that helps!

Stuart

pklove
Learner II

Just to be sure I have understood, your application (on localhost) is receiving all the expected LTI data but it is not matching any of your routes.

If that is the case, what language are you using and what route specification are you expecting to match?

Hi Peter.  Not exactly.  Let me see if I can explain better.

I have a VueJS/Node app running locally at 127.0.0.1:8080.  It has Express under the hood, of course. In my hosts file I have that point to canvas.kup.com:8080.  In my vue-router, I have a route for /lti_launch -- so that would be at 127.0.0.1:8080/lti_launch or canvas.kup.com:8080/lti_launch.  Either way, it fully resolves when I open that URL in a browser tab/window.  When launching from the Canvas editor, the Network traffic shows that it is requesting "https://canvas.kup.com:8080/lti_launch" but, for some reason, when it is being called from Canvas it terminates at a 404.  I only mentioned the LTI data before to say that it is the lti_launch POST I would expect to get from Canvas to have my app consume -- but it never gets to consume the POST because of the 404 termination.

The relevant Request Headers seem fine:

Unless I am missing something obvious, of course.  Simply put, though -- the app urls (i.e. https://canvas.kup.com:8080/<some endpoint>) resolve 200 everywhere except for within the Canvas LTI launch flow.

Please let me know if you need any other specifics.  I should note that I am developing on Windows 10 under the Windows Subsystem for Linux (Ubuntu).  Also to note is that there are other apps on the web that connect to this local app without issue -- this seems to be something specific to the Canvas environment that I am not accounting for or doing correctly.

dwahl_sales
Instructure
Instructure

Hi  @trip_gould ‌,

Correct me if I'm wrong, but this is your setup:

Production (internet-facing) Canvas

Dev (localhost) app on canvas.kup.com (or is it canvas.myapp.com?)

localhost DNS pointing canvas.kup.com to 127.0.0.1

Is this correct?  If so, when we look at the LTI implementation guide, we can see that the POST is generated by the Tool Consumer (Canvas) and NOT by the client device.  This means that Canvas is trying to post to canvas.kup.com and is using its DNS lookup to try to access the page, not your localhost DNS.

Overview of the LTI Implementation

Hi Danny,

What you have above looks correct re: my setup.  Note that canvas.kup.com is just the address of my local app (Tool Provider) -- not a canvas instance -- but, that said, I have also tried with plain localhost:8080 and 127.0.0.1:8080.  There must be a way to do local development as a Tool Provider against a running cloud instance of Canvas (Tool Consumer), no? 

I guess I'm missing something simple here.  I followed the docs at EduApp and various other tutorials around the web -- just to see if I can get a simple Hello World running off of my local as a Tool Provider and receiving the LTI launch from the hosted Canvas instance.

My guess is that my endpoint (/lti_launch) has to be a server API endpoint and not just a web route -- since the front end can't receive POST requests in that manner (unless there is some workaround of which I am unaware).  I'm assuming that was my mistake and misunderstanding when going through the docs.  So, for now, I'm trying to figure out how to drop into the Express server that is running under the hood of my vue-apollo app.

Thanks.

It doesn't work exactly like that.  Canvas returns a form to the browser with some javascript to auto-post the form to the tool provider.  So its actually the browser doing the DNS lookup.

See, for example Writing LTI Stuff: "The POST request must happen in the user's browser, which means it needs to be launched by submitting a form. Most of the time the form is submitted via JavaScript to an iframe rendered on a page within the consumer, so the user doesn't have an extra step when trying to launch an app"

And the diagram from 50581462‌ at https://community.canvaslms.com/message/125106-re-how-do-external-tool-sessionless-launch-urls-work?... 

trip_gould
Community Member

I figured out how to set up an endpoint on the GraphQL server using Express middleware, so that was all that was needed for receiving requests in this setup.  Now I just have to figure out how to get the apollo-graphql server to run over https://

View solution in original post