Celebrate Excellence in Education: Nominate Outstanding Educators by April 15!
Found this content helpful? Log in or sign up to leave a like!
Are there any Canvas API functions for managing Developer Keys? At the very least, I'd like to be able to view and to create API keys and LTI keys via the API.
Why?
My organization has multiple Canvas instances. One of them is a test instance that I use to test Canvas integration code I develop. However, that test instance gets wiped out and replaced with the contents of the production instance every two weeks. That means the API and LTI keys I had in the test instance are deleted every two weeks. Theoretically, I could probably create keys in the production instance for the test environment and let them get synced into place every two weeks. My managers do not want me to do that, though, citing security concerns.
I've been perusing the Canvas Live API for functions to work with Developer Keys, but I haven't found any.
I'd appreciate suggestions about this. Thanks!
For API keys there is a checkbox that limits the key to only work on the test instance, that might reduce the risk and mean you can create those keys on production and have them copied over the test/beta with all the other data.
Although it isn't documented 🙁 it does appear that there is an API endpoint for developer keys and I would expect you can create/update keys using the normal REST semantics:
https://instance.instructure.com/api/v1/accounts/1/developer_keys
the controller that handles these requests is:
https://github.com/instructure/canvas-lms/blob/master/app/controllers/developer_keys_controller.rb
If you get something working I would be really interested in hearing about it as it's something we were hoping to look into too.
Currently we have both our LTI and API developer keys installed on production and then copied to test/beta, the LTI tools aren't enabled in anything other than our testing sub-accounts so they don't show up or where anywhere but a limited set of courses.
Hi, @matthew_buckett.
Thanks for the response.
As it turns out, I noticed the undocumented API myself on Thursday last week. I used the Google Chrome developer tools to watch the network requests, then used the "Copy as cURL" feature to get the requests as curl commands. They included a lot of headers that are specific to the browser that I deleted, then I added an "Authorization: Bearer" header with my Canvas API token and it works great.
I have a couple of scripts for getting keys and for creating them. If anyone is interested in trying them, just tell me. I can tidy up the code and share it.
Thanks for the reference to the controller code in Canvas' GitHub repo, too!
I have an unfortunate update to this…
My personal Canvas API token seems to work with getting information about existing Developer Keys, but it does not work with creating them. I'm not sure whether I don't have enough access in my Canvas account to do this or maybe this can't be done with an API token.
I just had a quick look and it seems to work for me, I created a file called tool.json which contains:
{
"tool_configuration": {
"settings": {
"public_jwk": {},
"title": "Test",
"description": "Test",
"target_link_uri": "http://example.com",
"oidc_initiation_url": "http://example.com",
"public_jwk_url": "http://example.com/jwk",
"scopes": [],
"extensions": [
{
"platform": "canvas.instructure.com",
"settings": {
"placements": [
{
"placement": "account_navigation",
"message_type": "LtiResourceLinkRequest"
},
{
"placement": "link_selection",
"message_type": "LtiResourceLinkRequest"
}
]
},
"privacy_level": "anonymous"
}
],
"custom_fields": {}
}
},
"developer_key": {
"name": "Test Tool",
"redirect_uris": "http://example.com",
"scopes": []
}
}
then if I run this command (ccurl is a wrapper around curl that adds a 'Authorization: Bearer 12345.....' header to requests):
❯ ccurl -s -H 'Content-Type: application/json;charset=UTF-8' --data @tool.json https://oxeval.instructure.com/api/lti/accounts/1/developer_keys/tool_configuration | jq .
{
"tool_configuration": {
"id": 155,
"developer_key_id": 185,
"settings": {
"public_jwk": {},
"title": "Test",
"description": "Test",
"target_link_uri": "http://example.com",
"oidc_initiation_url": "http://example.com",
"public_jwk_url": "http://example.com/jwk",
"scopes": [],
"extensions": [
{
"platform": "canvas.instructure.com",
"settings": {
"placements": [
{
"placement": "account_navigation",
"message_type": "LtiResourceLinkRequest"
},
{
"placement": "link_selection",
"message_type": "LtiResourceLinkRequest"
}
]
},
"privacy_level": "anonymous"
}
],
"custom_fields": {}
},
"created_at": "2022-11-05T03:58:50-04:00",
"updated_at": "2022-11-05T03:58:50-04:00",
"disabled_placements": null,
"privacy_level": null
},
"developer_key": {
"email": null,
"user_name": null,
"created_at": "2022-11-05T03:58:49-04:00",
"user_id": null,
"name": "Test Tool",
"icon_url": null,
"workflow_state": "active",
"notes": null,
"scopes": [],
"require_scopes": true,
"test_cluster_only": false,
"client_credentials_audience": null,
"api_key": "msnbrNcg6MEWBFw5YcBmsEH7zLf3SPqPdDQSXkMvw3nFp1zttbNdmZkelzTANLie",
"redirect_uri": null,
"redirect_uris": "http://example.com",
"access_token_count": 0,
"last_used_at": null,
"vendor_code": null,
"public_jwk": {},
"public_jwk_url": "http://example.com/jwk",
"allow_includes": false,
"developer_key_account_binding": {
"id": 193670000000000200,
"account_id": 193670000000000000,
"developer_key_id": 193670000000000200,
"workflow_state": "off",
"account_owns_binding": true
},
"account_name": "Oxford Evaluation",
"visible": true,
"is_lti_key": true,
"id": 193670000000000200
}
}
This key then appears in the developer key list for that instance when looking through the web (I've since deleted this key). Maybe the problem you're seeing is permissions related?
Yes, I think so. I've contacted the Canvas product manager at UMich about it. I've been told that I have all the permissions that could possibly be granted to me in Canvas. However, it still doesn't work for me.
Maybe the request I'm sending has more headers than the bare minimum required. That could cause problems.
@matthew_buckett, when your request is sent, does it only have the "Content-Type" and "Authorization" headers? (And probably "Content-Length" automatically added by curl.)
I wasn't sending through any other headers than those on my command line. How are you making your request and how is it failing?
Has anyone been able to get this to work as an update? If I retrieve a developerkey and change one of the URLs then try to update it (POST) it just creates a new one if I try with (PUT) and just give me the following error "Value cannot be null. Parameter name: source"
Any idea's
I'm able to successfully make a PUT request, though all of the fields that I'm trying to change do not get updated in Canvas.
For example, I'm trying to update an existing LTI key to change the following fields:
tool_configuration["settings"]["target_link_uri"]
tool_configuration["settings"]["oidc_initiation_url"]
developer_key["redirect_uris"]
but only the last one actually gets changed. I've tried moving the "target_link_uri" and "oidc_initiation_url" settings to other places in the JSON structure, but nothing has worked so far. Sure would be nice if Instructure documented these endpoints!
(FWIW, the reason I'm trying to update these LTI keys is that when they get copied down from prod to the test and beta environments, we want to be able to change the URLs to point to our equivalent test and beta tool environments. With LTI 1.1 tools this can happen automatically, but for LTI 1.3 tools we currently have to go into the Canvas UI and modify every single one of them each time a refresh happens.)
@ColinMurtaugh This doesn't really address the problem you're having, but we setup all our dev/test copies in production, but then just installed the tools in a test sub-account. That way they persist through beta/test refreshes, it's not great, but it works.
If you get it working I'd be really interested.
We were trying to do the same exact thing, but I didn't have any luck updating only the pieces that I wanted to change (urls and domains, etc) and ended up just sending everything. It's a bit of a pain as we then have to make sure we keep everything in sync if we make a change to the prd settings for when we update beta/test.
Chris
That's what I was trying to do also I pulled back the key make a change and save it again but with no luck.
can you post your json structure of one that works
I still cannot get it to work I have tried it both ways as:
{
"developer_key":
{
"name": "NAME HERE",
"redirect_uris": "URL HERE"
}
}
and
{
"name": "NAME HERE",
"redirect_uris": "URL HERE"
}
I think it should be the first way that would work.
Here is the url I doing the PUT to: https://******.test.instructure.com/api/v1/accounts/1/developer_keys
but I still get the same error: Value cannot be null.Parameter name: source
I believe you want to send your PUT to /api/lti/developer_keys/<DEV_KEY_ID>/tool_configuration
The url is slightly different than every other api call.
Chris
I tried at did not get it to work:
Here are the to payloads i have tried
Payload 1:
{"developer_key":{"name":"Ivey Publishing","redirect_uris":"https://apps2.ivey.ca/lti_EXECED_TEST_AD1/IveyPublishing/Provider/Tool","id":96890000000000142}}
Payload 2:
{"name":"Ivey Publishing","redirect_uris":"https://apps2.ivey.ca/lti_EXECED_TEST_AD1/IveyPublishing/Provider/Tool","id":96890000000000142}
With the following URLs and the response status I received:
var urlQuery = $"/api/v1/accounts/{_Account}/developer_keys/{developerKey.Id}/tool_configuration"; //Test 1 - Response: 404
var urlQuery = $"/api/lti/accounts/{_Account}/developer_keys/tool_configuration"; //Test 2 - Response: 404
var urlQuery = $"/api/lti/accounts/{_Account}/developer_keys/{developerKey.Id}/tool_configuration"; //Test 3 - Response: 404
var urlQuery = $"/api/lti/developer_keys/{developerKey.Id}/tool_configuration"; //Test 4 - Response: 400
I know I am close I just cannot get over the last hurdle
I can update a tool configuration by supplying the whole configuration, so I created a tool as I described earlier (using curl) and then I updated the tool.json file to have a new title and redirect_uris, so the contents of the file is now:
{
"tool_configuration": {
"settings": {
"public_jwk": {},
"title": "New Test",
"description": "Test",
"target_link_uri": "http://example.com",
"oidc_initiation_url": "http://example.com",
"public_jwk_url": "http://example.com/jwk",
"scopes": [],
"extensions": [
{
"platform": "canvas.instructure.com",
"settings": {
"placements": [
{
"placement": "account_navigation",
"message_type": "LtiResourceLinkRequest"
},
{
"placement": "link_selection",
"message_type": "LtiResourceLinkRequest"
}
]
},
"privacy_level": "anonymous"
}
],
"custom_fields": {}
}
},
"developer_key": {
"name": "Test Tool",
"redirect_uris": "http://new.example.com",
"scopes": []
}
}
Then I ran this command:
ccurl -X PUT -s -H 'Content-Type: application/json;charset=UTF-8' --data @tool.json https://oxeval.instructure.com/api/lti/developer_keys/123450000000000123/tool_configuration | jq .
and it updated the LTI tool title and also updated the redirect_uris. I checked in the UI and it seems to have stuck:
The bit I got wrong was using the external tool ID instead of the developer key ID to perform the update and in the JSON response the developer key ID looks "wrong", but otherwise it seems to be "good enough".
One thing to watch out for is that you send the "Accept: application/json+canvas-string-ids" when working with developer keys as lots of the IDs are large and don't work correctly when processing the response with JavaScript. The problem of large numbers is also present in the command line utility jq, which will silently change your numbers (very fustrating, jq-1.6), here's an example of 678 getting changed to 670:
❯ echo '{"id": 123450000000000678}' | jq .
{
"id": 123450000000000670
}
To participate in the Instructure Community, you need to sign up or log in:
Sign In