After an outage on September 1, the Instructure Community is now fully available, including guides, release notes, forums, and groups. If some styling still looks unusual, clear your cache and cookies.
Found this content helpful? Log in or sign up to leave a like!
I'm starting the process of converting some Java-based LTI tools (Java is used for LTI validations, and also for proxying the Canvas API, although not on the client side) to the LTI 1.3 standard. If you are using Java in your development, what LTI 1.3 libraries are you currently using, or would you recommend? In addition, if you could point to examples of use of such libraries which do not require a Spring Boot application, that would be very helpful. I haven't seen much publicly available (I am aware of the libraries created at the UOC, although I found no examples of use for a regular web app -only one example is public, and is for a Spring Boot application-). Thanks!
We built a LTI 1.3 implementation for Spring Boot that builds on the Spring Security OAuth2 libraries:
https://github.com/oxctl/spring-security-lti13
there's a demo project that uses that library here:
https://github.com/oxctl/spring-security-lti13-demo
It's worked reasonably well for us and we've used it for all our more recent LTI tools.
I apologize if this is a repeat (I'm pretty sure I posted a reply earlier but somehow it did not get recorded!). Thanks Matthew for your reply (BTW, I enjoyed watching your LTI presentation at CanvasCon Online). Since my apps do not use Spring though, I was hoping somebody would have either done something for this type of (plain) Java app, or at least show an example of how their libraries can be used from such application (which is why I specifically asked for a non-Spring Boot type application example, although I appreciate your response in any case!). Could any of the libraries you've worked on be used without Spring?
Sorry when reading your message I complete missed the "not". I can't take credit for a CanvasCon presentation, I think it must be a different Matthew.
The Spring Security OAuth2 code (which the LTI 1.3 code uses), builds on the libraries from Connected2ID (https://connect2id.com/products/nimbus-jose-jwt), however writing a full LTI 1.3 implementation is a reasonable piece of work as LTI 1.3 is more complex than LTI 1.1
Thanks again for replying. And sorry for having confused you with a presenter at Canvas Con!. Yes, I agree that it's likely considerable work to start from scratch building an LTI 1.3 java app - although I'm pretty familiar with Java itself and have built many such non-Spring apps, but they were all using basic (open source) LTI libraries , so I'm going to have to decide whether to do all that work myself, or look for some other alternative which would also requite quite a bit of work too (e.g. converting my apps to use Spring Boot so I could use your libraries -or those from UOC-, etc.). Unless somebody else comes up with what I need before I start building it myself, of course, which would be the ideal :-). Thanks again for your input!
@matthew_buckett, Was looking at your library, but it seems more targeted for the Tool's side of the implementation. Do you know any Java libraries from the Platform's perspective? Right now I just need to do a POC for LTI 1.3 launch.
Sorry, I don't know any libraries out there for supporting the provider side of the launch, there is the Spring Security Authorization Server however I don't know how much more you'd need to add to support the LTI 1.3 launch. It is currently under heavy development and is probably a reasonable library to do any development against.
Hello Matthew,
I have tried your code it works.
But I cannot verify the the Signature in the LTI launch.
Any suggestion please? Thank you very much.
Could you explain which part isn't working please. Do you mean that you can't verify the signature on the JWK?
Hi Everyone! I just thought I'd say hello on this thread because I, too, am a java developer with existing tools (on LTI 1.1) and am seeking to update to LTI 1.3. (Our institution is in the process of moving to Canvas, and I'm updating my tools at the same time.).
As a first step, just to help with my learning, I used the IMS Global's LTI 1.3 Reference Implementation to create a "dummy platform" and "dummy tool" and got them talking to each other successfully. (confession, that took me the better part of a day because I had to slow down and get acquainted with all the configuration options!). I also highly recommend this video. I watched it twice!! https://www.youtube.com/watch?v=qHStELNsYyI
As a second step, I'm very grateful for the library above. Thank you Matt! I downloaded it from github and got it running. I don't usually use Spring Boot either, but, the whole LTI 1.3 process is more complicated than my whole LTI app, so, it's easier for me to rewrite my app from scratch based on a working LTI template than it is for me to start over with LTI in my existing app's structure.
So, building off my experience above, my goal is to get the "dummy platform" talking instead to the spring-security-lti-demo. I don't quite have it working because the IMS reference implementation is giving me an unhelpful Rails error. So, I'm watching lots of nerdy technical talks to teach me about Oauth2 and I'm combing through the http parameters at each step of the launch flow.
For me, it's failing on the authorization request step, where it's trying to go back to OIDC Auth URL (https://lti-ri.imsglobal.org/platforms/xxxx/authorizations/new). It's an HTTP 500 Internal Server Error on the IMS Reference implementation side (the "dummy platform"). I'm quadruple checking the public and private keys, etc, but have not yet figured it out.
Anyway, if there's community here of others in a similar situation, I'd be very happy to share experiences. Even if we get stuck at different steps, it helps to learn the stuff overall with others!
Steph
Thanks for your post @iosparkletree1 ! Sure, it'd be nice to share experiences as we pursue our respective LTI 1.3 conversions! My disadvantage with respect to IMS resources is that I only have access to their public docs (and, I believe, there's public access to their reference implementation but not to all of their tools, for example, which is unfortunate). I might start with a real platform instead of coming up with a 'dummy' one (since I could test a tool against the Canvas platform; which could be quicker ). In any case, I'll take a look at what IMS offers just in case. BTW, thanks for pointing out to the You Tube webinars from the IMS. I had not watched that one yet, and I also found it pretty useful, as you commented.
It's great to have a place to reach out and be not alone!
I, too, only have access to the IMS public docs.
I am quite stuck in my attempts to connect the IMS LTI 1.3 Reference Implementation "dummy platform" with spring-security-lti-demo. So, I next tried to connect to different java library, Unicon's: https://github.com/Unicon/tool13demo. Even though I got this up and running too, unfortunately I'm again sstuck with a Rails error on the reference implementation site at the authorization request step.
I didn't even try connecting to either of these tools with Canvas, because I thought I should build up everything from the reference implementation first. But, I'm so stuck I'll try anything!
A disadvantage that I have is that I'm a developer, not an admin, so I don't have permission to adjust any of our institution's developer keys. I have to submit tickets to a colleague to set it up for me, which makes it difficult to explore with trial and error. But, on the plus side, we learn together!
Best wishes with your configuration. Here's hoping that one day soon, we'll both be working on our actual tools, once we get past the barrier that is LTI 1.3's complexity.
(edit: typo)
Whilst it is not quite complete, I believe it is working, so anyone in need of a testing platform for LTI 1.3 may like to try out the updated version of saLTIre at https://saltire.lti.app/platform and/or https://saltire.lti.app/tool. I hope to complete the update within the next week.
Cool thanks svickers2, good to know!
Here's the latest from me. As I mentioned, I tried a couple examples (spring-security-lti-demo and tool13demo) but couldn't get either to work against the IMS Reference Implementation (lti-ri). I am really perplexed because they should work. I even emailed the IMS Global info address to ask if you have to be a paying member to be able to use the lti-ri. They responded that I should be able to use it for Deep Linking, Assignment and Grades and Names & Roles.
As a stab in the dark, I decided to try getting them to run against our Canvas instead of the lti-ri.
To do that, I had to deploy to our test server, because the Canvas test server wouldn't be able to communicate with my development machine, which is on a hidden part of our network. So, I tried to deploy spring-security-lti-demo to a test server but discovered that Spring boot 2 requires Tomcat 8. Unfortunately, my institution has not yet upgraded and are still on Tomcat 7. So, I can't use spring-security-lti-demo. Tomorrow, I'll try tool13demo.
It is tempting to try the testing platform offered by svickers2 instead of the lti-ri, but I'm not familiar enough to know how to fill in all the options correctly!
It still nags me that I couldn't get the applications from github running against the lti-ri because those should work right out of the box.
@iosparkletree1 Although I have had spring-security-lti-demo working against LTI 1.3 reference implementation I have run up against some errors where the messages aren't very helpful (500 errors from lti-ri) although Canvas doesn't alway give great error messages it doesn't seem to fail as badly.
You should be able to perform a LTI 1.3 launch against Canvas using all localhost URLs and so not need things to be deployed onto a public address. As long as the browser you are using can access both Canvas the LTI tool it should work. The JWK Method should be set to "Public JWK" and not "Public JWK URL" when running a tool on localhost as that's the only URL that Canvas needs to access (rather than the browser).
When working and deploying Spring Boot applications I don't normally deploy it to an external tomcat but use the built in copy of tomcat. When in development I use maven to run the whole lot `mvn spring-boot:run` and when in production we build a fat JAR that contains Tomcat and is executable `java -jar build-jar-from-project.jar`
Sorry you're hitting so many bumps in the road, there should somehow be an easier way to get a LTI tool up and working.
Oh... I just realized... tool13demo is also Spring Boot. @pgo586 Now I fully appreciate your need to find a java library that is not Spring Boot!! We really don't have many options, do we?
There was a third option, UOC's java-lti-1.3, but it requires that you get Maven talking to GitHub. So far, I've been unsuccessful. But, this may be the promising option at this point.
Dear Matthew, I so appreciate your comments, thank you.
Oh you're right, of course I should be able to test against Canvas from my localhost, just the same as I could test against the lti-ri. I still get mixed up about what happens at the platform vs. tool sides, and who needs to access what JWK and from where.
I am sad that I won't be able to use spring-security-lti-demo for your codebase is really lovely. At my institution, a developer like me deploys our code to Tomcats that are hosted on servers that are quite locked down. I don't have access to the machines themselves, only the Tomcats, because another department is in charge of the OS, the tomcat patching, security, etc. I think this is actually a good thing, but as a result it may be a considerable feat to arrange to deploy my application separately with its own built-in Tomcat.
Thanks for your advice on configuring the Canvas JWK method.
Well, I'm going to go see if I can figure out the github tokens that seem to be a requirement to be able to import UOC's library in maven. I'm sure I'll be back to keep you all posted. 🙂
I resolved my trouble with the github token + maven and was able to run UOC's java-lti-1.3. Unfortunately, without my having changed any of the original code, I'm getting:
com.auth0.jwk.SigningKeyNotFoundException: Cannot obtain jwks from url https://lti-ri.imsglobal.org/platforms/68/platform_keys/60.json.
The URL of course is a now very familiar pointer to the lti-ri. When I visit the URL with my browser, it correctly gives a JSON result. I'd like to trust that both parties, the github project and the lti-ri, are both being presented in good shape without errors. But given these, I don't know what could be causing the error.
Although I hate to admit defeat, at this point I might sadly give up on LTI 1.3 for a while and instead do something with iFrames and our institution's single sign on (CAS).
Best wishes to you other java developers!
EDIT: Nope, I'm not gonna go down the iFrame route. It is gross and wrong. I regretted it as soon asa I typed it. LOL! LTI has to be the answer.
I know - I'll ask the systems people at my institution if there might possibly be a chance to provide me with a Tomcat 8, and see if I can deploy spring-security-lti-demo as a .war to the external tomcat.
Hi @matthew_buckett could I ask your advice? I want to try and get running spring-security-lti13-demo with Canvas. First, my institution's canvas admins need to give me a developer key. To help them do this, I have to send them the Redirect URI, Target Link URI, and Open ID Connect Initiation Url. From what I can tell from the README on github, I think it would be:
Redirect URI: https://localhost:8443/oauth2/login
Target Link URI: https://localhost:8443/
Open ID Connect Initiation Url: https://localhost:8443/oauth2/login_initiation/canvas
Additionally, I need to send them the Public JWK. I believe I should be able to copy and past this from https://localhost:8443/config.json but whenever I visit this the application asks to Please sign in. Maybe I'm supposed to use the Canvas developer key and secret here, but I don't have those yet. Is there a way I can what config.json looks like before registering with the provider?
Thank you very much!
@iosparkletree1 Ok, I should have double checked things, I've just run through setting up the tool and I think in an earlier commit I changed the URLs and didn't update the documentation (sorry for the confusion and time wasted). I've updated the Github repo with what should be the correct URLs and I've added a Wiki page outlining the manual settings if the config.json isn't working https://github.com/oxctl/spring-security-lti13-demo/wiki/Canvas-Manual-Installation. I've also fixed a problem with cookies not working correctly with modern browsers.
Basically I think it should be (/lti/ instead of /oauth/):
Redirect URI: https://localhost:8443/lti/login
Target Link URI: https://localhost:8443/
Open ID Connect Initiation Url: https://localhost:8443/lti/login_initiation/canvas
Managing developer keys is an individual permission so you could try asking your admins to create a role with that permission and then grant you that role. All Canvas deployments normally have 3 instances (prod/beta/test) and so maybe they could allow you to use the test instance and that way you can't break anything on production?
The config.json URL should always be public, so I'm a little confused as to why it's asking for authentication.
Hi Everyone! In case it helps someone, here are videos I made that document everything I did. I feel like I'm close to getting it working, but there must be something I'm doing wrong.
@matthew_buckettMy humblest apologies for anything wrong I may have done to your codebase. 😅
LTI 1.3 Reference Implementation setup for N00bs (works!!)
https://www.youtube.com/watch?v=Llk-t8sN3zo
spring-security-lti13-demo (not working...)
Hello @iosparkletree1 thank you for sharing the youtube link here. Can you please let us know once you able to run the application how it will look like and how you can able to login to the localhost?
Hello SurajPaigude,
Yes indeed I got the Oxctl library working, and in fact have used it in multiple projects in the years since my post above. It has been a great and reliable implementation and I would definitely recommend it! (Kudos Matthew!)
I'll tell you a bit about my development environment in case it is helpful. I use Eclipse with a Tomcat server set up in the environment. When it's time for me to use my application, I start up the Tomcat which initializes the Spring Boot as usual. So, the app is running on my localhost and listening to port 8080. Next, when I want to interact with my app, I go to my institution's Canvas server. In the Canvas Admin, I have already set up Developer Keys for LTI. The URLs point to my localhost. I know it's kind of funny to put 'localhost' into the Canvas server settings! This means that anyone who accesses the LTI links within Canvas is going to need to have the application running on their own localhost! But, this is sufficient for me, because I'm the only person who uses this particular key. With my Tomcat still running, I go into my Canvas course and I click on the LTI link for my application. Canvas sends the requests to my app and the handshakes all happen, and then I'm able to successfully interact with my application through Canvas.
When it's time for production, I use Eclipse to create a WAR file which I deploy on my institution's production Tomcat server. Next, we have different production Developer Keys for LTI where the URLs point to our production Tomcat server instead. Now, because everyone has access to the production Tomcat server, then anyone can use those LTI links in Canvas!
I hope this helps and I wish you the very best of luck! It takes a lot of work and trial and error and help from communities like this! I remain grateful to everyone for the support I myself received here!
best, Steph
Once again Matthew your advice has been a lifeline!
I downloaded the newest spring-security-lti13-demo. Now it's making it all the way into the second leg of the launch flow - getting closer!
I'm not getting the Rails error anymore. It seems it was caused by my adding something to your codebase that I shouldn't have while trying to solve a different error. To the Lti13DemoApplication class I wrongly added @ComponentScan(basePackages= {"uk.ac.ox.ctl.lti13.demo.controller.lti13"}). When I remove this, it seems to make it further through the launch flow.
Today, I can use the lit-ri to click a Resource Link from the platform, do the login initiation request, then the authorization request, and then send the JWT to the spring-security-lti13-demo. That's when it gives an error (screenshot).
For now, I've followed your suggestion, thank you, to ask my institution's Canvas admins if they will grant me the ability to create Developer Keys on our Test instance. I'll try running this against Canvas to see if that works any better.
Ok, I think you are missing the root certificate that's signing the HTTPS certificate used by https://lti-ri-imsglobal.org
I think the simplest solution might be to upgrade to a newer version of the JDK. https://community.letsencrypt.org/t/ssl-certs-in-java/15450 indicates that newer versions of JDK 7/8 include the required root certificate.
I tend to use JDK 11 for things as it's a long term support release, but has some nicer features than the older JDKs.
(NB. I think your messages are getting moderated as I only just got notified about your reply)
IT WORKED! I updated to Java 11 (and also my Eclipse IDE) and it worked without any other changes. (To show my appreciation I've just made a small donation to the British Heart Foundation.) Thank you @matthew_buckett !
Yeah, I feel a bit sheepish toward the Canvas Community moderator: I tried posting my reply about 5 times, maybe more, throughout the weekend. I thought I was doing something wrong, like pressing the wrong Reply button. My posts would simply disappear after I submitted them and I didn't realize it was because I was being moderated. I don't know what changed since my earlier messages were accepted instantly. Maybe I was asking too many questions. 😅 Anyway, thank you Canvas Community moderator! I appreciate what you are doing behind the scenes because I know it makes this a good place to work.
More good news, I've been granted a Dev Key Admin role on our Canvas Test instance. It seems that because the test instance is reset monthly, I'll lose the permissions each time, so, I'll have to re-ask for them monthly. Hopefully it isn't too tedious for our Canvas admin.
Best wishes everyone.... I'm thinking of you too @pgo586 and hope you're closer to a solution yourself!
Stephanie
Great to hear the good news @iosparkletree1 (or Stephanie)! . I have not started with my project yet; hopefully I can use some of the wisdom shared in this thread to succeed myself when I do start. I imagine I might post a few questions myself at that point. Hope I can count on those of you in this thread to help as needed too!
Best wishes!
@iosparkletree1 Well done 🎉 The donation is a really kind thought, thanks. I'm always happy to help. I think the error with the UOC code was also related to the certificate chain, but it was only with the fuller exception stack traces that it became more obvious. Locally we have a script that re-promotes admins on test/beta systems each Sunday (after the refresh).
@pgo586 If you get stuck just drop a message on the thread. I know you are keen not to use Spring Boot, it may well be possible to remove the Spring stuff from one of the Java LTI libraries but I don't have the time at the moment to look at this and it's not work related really.
Hello @matthew_buckett , me again, if I may.... How do I obtain the user_id/course_id/role(s) of the user? I believe this information is sent by the Platform on the last step of the launch flow within an id_token. However, I'm having trouble finding it. Would it be in a Bean? Would I need to modify any of the classes in the other project, not the demo but spring-security-lti13?
My tool is an infographic that needs to know the user_id/course_id/role(s) in order to call up the correct data.
Thank you very much!
I think I got it. You need the SecurityContextHolder. I believe you get access to it if your class is a @Controller. For me, I have the following in a Struts2 Action method (for now):
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
DefaultOidcUser principal = (DefaultOidcUser) authentication.getPrincipal();
Map<String, Object> attributes = principal.getAttributes();
Map<String, Object> customFields = (Map<String, Object>) attributes.get("https://purl.imsglobal.org/spec/lti/claim/custom");
String finallyGotTheUsername = customFields.get("canvas_user_login_id"); //gotcha!
There's a lot of background behind the above code snippet.... I also had to go into the Canvas Developer Key, under Additional Settings, Custom Fields, and add the following:
canvas_user_login_id=$Canvas.user.loginId
Sorry, I didn't get a notification for your first reply (just when you'd solved it).
Nice one, that looks right, the LTI library uses Spring Security which is why all the details end up being retrievable from the SecurityContextHolder. LTI does also pass across an opaque ID which is the same for a user between launches but isn't related to any of the users details in Canvas. But the opaque ID isn't any use if you want to call Canvas APIs or other local APIs passing across the current user.
Hopefully, this trail isn't too cold @matthew_buckett as I've got a question on troubleshooting the tool you've developed. I've got Canvas running in Docker on my localhost. I've modified spring-security-lti13-demo as suggested. I've followed the auto-discovery (https://github.com/oxctl/spring-security-lti13-demo) as well as the manual configuration instructions (https://github.com/oxctl/spring-security-lti13-demo/wiki/Canvas-Manual-Installation) but in both cases when I try to access the installed tool via Canvas I get a message that the tool doesn't respond. I'm certain the problem is on my end though I'm not sure how to troubleshoot. I'm hoping to get some pointers. I've turned on DEBUG level logging in IntelliJ but am not seeing any interactions.
Should the tool be running in Java 8 or Java 11?
The tools should work with anything from Java 8 up, although I recommend using at least Java 11 and ideally Java 17 as that will be supported for the longest.
Are you able to access the tool directly through your browser? By default this will be on https://localhost:8443/ and you should see a screen similar to the one attached to this post.
If you are running through docker the port that the tool is listening on may end up being different from the one in the configuration file.
I get that screen when I hit:
When I browse to https://localhost:8443 I get "The site can't be reached"
What URLs do you have configured in the developer key configuration?
Redirect URIs: https://localhost:8443/oauth2/login
Target Link URI: https://localhost:8443
OpenID Connect Initiation Url: https://localhost:8443/oauth2/login_initiation/canvas
If you aren't using HTTPS (and port 8443) then you want to update the URLs in the developer key to match. So you should replace https://localhost:8443 with http://localhost:8080
It's normally better to run with HTTPS enabled as it stops all the browser warnings and allows some additional features to work (that aren't available on HTTP).
Ugghhh. Even as I'm pasting in those URLs for whatever reason it didn't occur to me to setup Canvas for SSL/TLS. Thanks so much for being gentle in your response back to me. You are too kind.
Thank you!
Hi @matthew_buckett I'm trying to run(https://github.com/oxctl/spring-security-lti13-demo.git) application through my inbuilt tomcat,
Getting below error,
Description:
Parameter 0 of method namesRoleService in uk.ac.ox.ctl.lti13.demo.Lti13Configuration required a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' in your configuration.
Can you please help here?
Hiya @SurajPaigude ,
The LTI library requires a ClientRegistrationRepository bean, this holds details of all the Canvas servers (or other services implementing LTI) that you wish to allow to use your tool. Spring Security will create one of these beans if it finds any configuration for client registrations.
The way I setup configuration when developing locally is to create a folder called `config` in the root of my project and then add a file called `application.properties` inside it. If you run the Spring Boot application from the root of your project (or set that to be it's working directory) then it should automatically pull in the config from that file. https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-confi...
Then in that file you should configure the details for the service that is connecting to your LTI, there are instructions in the README but you probably want some lines similar to these (updating the client ID for the config from Canvas):
spring.security.oauth2.client.registration.canvas.client-id=1234
spring.security.oauth2.client.registration.canvas.client-secret=secret
spring.security.oauth2.client.registration.canvas.authorization-grant-type=implicit
spring.security.oauth2.client.registration.canvas.scope=openid
spring.security.oauth2.client.registration.canvas.redirect-uri={baseUrl}/lti/login
spring.security.oauth2.client.provider.canvas.authorization-uri=https://canvas.instructure.com/api/lti/authorize_redirect
spring.security.oauth2.client.provider.canvas.token-uri=https://canvas.instructure.com/login/oauth2/token
spring.security.oauth2.client.provider.canvas.jwk-set-uri=https://canvas.instructure.com/api/lti/security/jwks
spring.security.oauth2.client.provider.canvas.user-name-attribute=sub
I hope that allows you to get a little further.
To interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign inTo interact with Panda Bot, our automated chatbot, you need to sign up or log in:
Sign in