The Instructure Community will enter a read-only state on November 22, 2025 as we prepare to migrate to our new Community platform in early December.
Read our blog post for more info about this change.
Found this content helpful? Log in or sign up to leave a like!
I am working to verify OAuth Signatures coming from our LTI posts.
I am looking for descriptive and detailed documentation on how I should be creating the OAuth Signature on my end. I got the basics of using HMAC_sha1. I am trying to find the doc’s describing what should EXACTLY should be hashed.
I have poked through your source code and it appears you are using a canvas specific ruby gem for creating this signature. Without me dissecting what you are doing, are there any docs out there?
In searching around I came across this resource. In a google discussion (https://groups.google.com/forum/#!topic/canvas-lms-users/JfoNmPECpqE), Deactivated user says, I can use this to "display the oauth base string before it is hashed.” Is this still accurate?
https://lti-tool-provider.herokuapp.com/
This issue refers to some spec docs, but I have not been able to locate those.
https://github.com/instructure/canvas-lms/issues/600
Any help and direction would be much appreciated.
Canvas course has training on OAuth signature
Hi Martin,
This course unfortunately does not describe how you create a signature but rather just keeps posting requests for you to try to authenticate.
I am looking for the exact method for the way in which Canvas creates it signature string prior to hashing.
The hash is calculated on the entire response body minus the oauth nonce, plus the destination (your server's) url, and the HTTP verb (which is always POST). I found this code instructive.
This is where I started and frankly what made the most sense to me. However I read this Google Groups and Brad Humphreys sent me to thos oAuth Signature - LTI then was led to believe that they were hashing params even if they were not being sent with the request.
Thanks for your insight, I am going to try that out again today.
Also - you mention minus the nonce, from everything I have read, it is minus the signature.
Ok I just succeeded. Thanks for getting me back on this path. It made so much more sense to me than the google groups thing I posted earlier. I couldn't imagine and really didn't want that to be the solution.
Honestly the frustrating part was just that there were so many pieces in so many places. The solution is very simple, only it is laid out. I will be posting a document on the community soon so that no one has to go through this guess and search work again.
@mwhite I am having same issues as you but I can't figure it out. Did you post this document anywhere? I will appreciate any kind of help. Thanks!
Figured it out. In my case having /' broke everything. So watch out for: ' in values.
I did in fact figure my problems out, glad you did as well!
There are def some gotcha's out there, like if the student has a tilde in their name. I am putting together all my notes on oauth signatures and hope to have a nice comprehensive doc published soon.
@mwhite , did you ever create that document? I can sign my POST requests just fine, and they are being authorized. But I can't validate the signature from the LTI launch request, I always get a different signature and I have no way of knowing what I'm doing wrong. Thanks.
Ok I just figured it out. I'll leave some information here for anyone that gets stuck in this problem as well.
Just go to this website http://lti.tools/oauth/ , and you can actually customize the request that is being signed. So you just put the request that you want to sign there and the different steps will be updated to match the request you just typed.
Then you just need to compare it with what you're doing. Go step by step and see if everything matches.
In my case it was a problem with the encoding method that I was using. It was replacing whitespaces with the plus sign, and it should be replacing it with %20 as it is in the guidelines. If it wasn't that website I wouldn't have found the problem.
@mwhite there is a nice tutorial here: http://lti.tools/oauth/
For those who do not want to fight the oAuth battle, I recommend finding a standard library for the language you are using.
For those who simply love the challenge, it's a matter of getting the sequence of events just right, I overlooked an iteration of url encoding which set me back on time to figure out. Running across the link above helped quite a bit.
Thanks @garth - frankly I have plenty of challenges and was hoping not to take this one on but I'm working with Play Framework in Scala and no one has written this package yet.
I'm working my way through it now and have the signature portion complete.
In Ruby I found the following code works to check the signature:
begin
signature = OAuth::Signature.build(request, :consumer_secret => $oauth_secret)
signature.verify() or raise OAuth::Unauthorized
rescue OAuth::Signature::UnknownSignatureMethod, OAuth::Unauthorized
return %{unauthorized attempt. make sure you used the consumer secret "#{$oauth_secret}"}
end
I placed this code just after the start of the route where the LTI tool is invoked. Note that this code is for a prototype and not for production use, as one would not want to disclose the secret!
This assumes that you earlier loaded the libraries via:
require 'oauth'
require 'oauth/request_proxy/rack_request' <<<< I'm not sure this is necessary if you just want to verify the signature
Documentation on the Ruby Oauth library is at Module: OAuth::Signature — Documentation for oauth (0.2.4) .
This is exactly what I ended up using to verify signature with PHP:
Mariusz, thank you so much for your helpful code. I finally was successful at verifying the signature by making one edit to your code, right at the top. It is shown below for the next person stuck at this point.
You are a great community, thanks for all your help!
function verify_requests_signature($secret) {
$url = (($_SERVER['HTTPS'] === 'on') ? 'https://':'http://') . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$url = rawurlencode(utf8_encode($url));
$data = $_POST;
$requested_signature = $data['oauth_signature'];
unset($data['oauth_signature']);
$data_encoded = array();
foreach ($data as $key => $val) {
$data_encoded[] = $key.'='.rawurlencode(utf8_encode(stripslashes($val)));
}
asort($data_encoded);
$data_encoded = implode('&', $data_encoded);
$data = rawurlencode($data_encoded);
$secret = $secret.'&';
$sig_base = 'POST&'.$url.'&'.$data;
$our_signature = base64_encode(hash_hmac('sha1', $sig_base, $secret, true));
return ($requested_signature === $our_signature);
}
Hi David,
I am starting the LTI integration for our app and came across this helpful post, but I am kind confused, is the LTI v1.3 changed anything regarding the oAuth signature and the methodology that canvas using in the post requests or it's still the same ?
This thread is about LTI 1.1 which is built on top of OAuth 1.
LTI 1.3 (the newly released standard) is build on top of OAuth 2 and OpenID Connect (OIDC).
LTI 1.3 is substantially more complex than LTI 1.1 but is more secure and allows you to use some services without requesting an OAuth token on behalf of the user.
David's code worked successfully for me to verify signature. Thank you so much!! However, is it still necessary to check the oauth_nonce field to mitigate replay attacks?
we are getting a failure when Canvas allows special char in the Name such as TM or whatever. How can this function be altered to help with this?
Community helpTo 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