HI Brad,
Following up with the non-match: I was able to reproduce the issue and found that your LTI signature verifier reproduced my signature (from my oAuth functions) but not yours (sent as a parameter to my external tool page) under the reproducible circumstance.
This authenticates: Install a tool as a course level external tool for learners, while I'm logged in as administrator, and call the tool while still logged in as administrator.
This fails: Log in as a learner and call the tool from the course. There is either a.) a discrepancy with Canvas' signature generation when a learner calls the tool, or b.) the same discrepancy both in my logic and your LTI siguature verifier, because they both agree on what the signature should be.
I've compared the parameters sent to my external tool page. One thing I notice when I'm a learner is that there is an additional parameter passed in:
lis_person_sourcedid: 123456
This parameter does not appear for the admnistrator, nor does it appear in the LTI signature verifier. If I have more time today, I'll add that as a parameter to my code, and see if it matches your signature. If you can't reproduce this issue, then email me privately and I'll provide you with the location of the site page and a login.
tnx
Steve