Skip to content

Instantly share code, notes, and snippets.

@dennisleexyz
Last active January 8, 2023 16:46
Show Gist options
  • Save dennisleexyz/8ee7552e6fafd50ba2375a05c51a12f7 to your computer and use it in GitHub Desktop.
Save dennisleexyz/8ee7552e6fafd50ba2375a05c51a12f7 to your computer and use it in GitHub Desktop.
Extract Canvas LMS API token from Android app data

Extract Canvas LMS API token from Android app data

Canvas LMS is a learning management system for school classrooms. An application can use the API to access data, but only with an API token. Some integrations require a token manually generated from the user's settings page.

Some institutions don't let you generate one. This page will discuss extracting a token manually from a rooted Android device signed in to the user's account on the Canvas Student app as of version 6.21.2 (246).

Two files, both in /data/data/com.instructure.candroid/shared_prefs/, contain the accessToken:

/data/data/com.instructure.candroid/shared_prefs/canvas-kit-sp.xml
/data/data/com.instructure.candroid/shared_prefs/signedInUsersList.xml

A sample Python script requiring parsel is provided for extraction.

The token is directly in the XML element.

XPath CSS
//map/string[@name="accessToken"]/text() map > string[name=accessToken]::text

The token is in a JSON object within the XML element, where all the quotes are escaped as ".

XPath CSS
//map/string[@name]/text() map > string[name]::text
#!/usr/bin/python3
import json
from parsel import Selector
map = {
'canvas-kit-sp.xml': {
'css': 'map > string[name=accessToken]::text',
'xpath': '//map/string[@name="accessToken"]/text()',
},
'signedInUsersList.xml': {
'css': 'map > string[name]::text',
'xpath': '//map/string[@name]/text()',
},
}
token = None
for file, selector in map.items():
try:
read_data = open(file).read()
inner_tag = Selector(read_data).css(selector['css']).get()
inner_tag = Selector(read_data).xpath(selector['xpath']).get()
try:
token = json.loads(inner_tag)['accessToken']
except json.decoder.JSONDecodeError:
token = inner_tag
except:
pass
if token:
print(token)
else:
raise Exception
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="api_protocol">https</string>
<string name="pandataInfo">{&quot;auth_token&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;expires_at&quot;:00000000000000000000,&quot;xxx&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;props_token&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;}</string>
<boolean name="canGeneratePairingCode" value="false" />
<string name="domain">canvas.xxxx.edu</string>
<string name="client_secret">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</string>
<string name="accessToken">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</string>
<boolean name="canvasForElementary" value="false" />
<string name="user">{&quot;avatar_url&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;calendar&quot;:{&quot;xxx&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;},&quot;effective_locale&quot;:&quot;xx&quot;,&quot;enrollmentIndex&quot;:0,&quot;xxxxxxxxxxx&quot;:[],&quot;xx&quot;:00000,&quot;xxxxxxxxxxxxx&quot;:false,&quot;xxxxxxx&quot;:false,&quot;xxxxxxxx&quot;:&quot;xxxxxxxxxxxxxxxx&quot;,&quot;name&quot;:&quot;xxxxxxxxxx&quot;,&quot;primary_email&quot;:&quot;xxxxxxxxxxxxxxxx&quot;,&quot;short_name&quot;:&quot;xxxxxxxxxx&quot;,&quot;sortable_name&quot;:&quot;xxxxxxxxxxx&quot;,&quot;Don\u0027t use me for serialization&quot;:-1}</string>
<string name="user_agent">candroid/6.21.2 (246)</string>
<string name="client_id">000000000000000</string>
<string name="refreshToken">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</string>
<string name="token"></string>
</map>
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="canvas.xxxx.edu-00000">{&quot;accessToken&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;canvasForElementary&quot;:false,&quot;xxxxxxxx&quot;:&quot;xxxxxxxxxxxxxxx&quot;,&quot;clientSecret&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;domain&quot;:&quot;xxxxxxxxxxxxxxx&quot;,&quot;protocol&quot;:&quot;xxxxx&quot;,&quot;refreshToken&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;token&quot;:&quot;xxxxxxx&quot;user&quot;:{&quot;xxxxxxxxxx&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;,&quot;calendar&quot;:{&quot;xxx&quot;:&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;},&quot;effective_locale&quot;:&quot;xx&quot;,&quot;enrollmentIndex&quot;:0,&quot;xxxxxxxxxxx&quot;:[],&quot;xx&quot;:46379,&quot;xxxxxxxxxxxxx&quot;:false,&quot;xxxxxxx&quot;:false,&quot;xxxxxxxx&quot;:&quot;xxxxxxxxxxxxxxxx&quot;,&quot;name&quot;:&quot;xxxxxxxxxx&quot;,&quot;primary_email&quot;:&quot;xxxxxxxxxxxxxxxx&quot;,&quot;short_name&quot;:&quot;xxxxxxxxxx&quot;,&quot;sortable_name&quot;:&quot;xxxxxxxxxxx&quot;,&quot;Don\u0027t use me for serialization&quot;:-1}}</string>
</map>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment