After many days of frustration, I found the solution. Hope this helps someone, especially since large part of my frustration was seeing people with the same problem as me in this forum who never posted how they solved their problem.
Anyhow, the answer to this problem was incorrectly configured environments. For context, I tried this on four different environments. The quick-start development, the quick-start production, bitnami (cloud), and IONOS.
Here's a rundown of each one:
- Quick-start development could've worked, but I believe I skipped this step, since I really didn't care that much about extra performance. As the production quick-start mentions (but not the development one for some reason???) "there are some features of Canvas that require redis to use, such as OAuth2," and if you're implementing LTI you'll know that you use OAuth2. So, if you don't install redis you will come across errors when developing your LTI tool.
- IONOS doesn't work at all for LTI 1.3 since they are not using an updated version of canvas so LTI 1.3 is not supported.
- Quick-start production and bitnami both face the same issue, not properly configured dynamic_settings.yml. In the case of bitnami, the example one wasn't even touched, dynamic_settings.yml didn't even exist (only dynamic_settings.yml.example). Quick-start production does have a section about it, but no indication that this is something that is required if you want LTI 1.3 to work. In fact, even if you copy the dynamic_settings example file like the production section suggests, it still won't work. You see, even though the example files often have a development property and a production property, dynamic_settings doesn't. It actually only has a development property! To fix it, I simply changed development to production, and assuming everything else is configured properly your LTI integrations should begin to work. Reason why this is necessary is because this file actually contains the JWK's necessary to sign the token in launch initiation or to respond to the /api/lti/security/jwks endpoint. There was 0 indication online at all that this was necessary, and I found this out by looking through the source code.
If any canvas developers see this, please do me a favor and update the quick-start guides to avoid this issue. On the development quick-start, please mention that redis is necessary for OAuth to work, since somebody who is developing will go straight to the development quick-start and will not have this information. And in the production quick-start, please note that LTI won't work without reconfiguring dynamic_settings.yml, and maybe add the production example so that it can work straight out of the box by copying dynamic_settings.yml.example.
At the very least, anybody with this issue will hopefully stumble upon this thread and I sincerely hope it helps.