We are using LTI 1.0 and oauth 1.0.
How to use the ‘lis_outcome_service_url’ and ‘lis_result_sourcedid’ to issue a simple grade posting without getting malformed OAUTH header error. Is there a required credential setup here to make this work?
The POST of the URL IS getting to the site but Poatman is probably not setup correctly. Is there a way to configure the LMS to allow my server to server communication to work? Not sure what the method is
We are seeing this error in the returned XML:
<?xml version="1.0" encoding="UTF-8"?>
<imsx_POXEnvelopeResponse xmlns = “http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0”>
<imsx_POXHeader>
<imsx_POXResponseHeaderInfo>
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>999999123</imsx_messageIdentifier>
<imsx_statusInfo>
<imsx_codeMajor>failure</imsx_codeMajor>
<imsx_severity>status</imsx_severity>
<imsx_description>OAuth verification error: Malformed authorization header</imsx_description>
<imsx_messageRefIdentifier>
</imsx_messageRefIdentifier>
</imsx_statusInfo>
</imsx_POXResponseHeaderInfo>
</imsx_POXHeader>
<imsx_POXBody></imsx_POXBody>
</imsx_POXEnvelopeResponse>
THanks,
Joe
Turn out its pretty straight forward with the relevant headers:
Here is the postman log…
POST bssn.education - This website is for sale! - bssn Resources and Information. ms
Warning: Self signed certificate
POST /courses/course-v1:KIMO_U+Torque_101+2021_Fall/xblock/block-v1:KIMO_U+Torque_101+2021_Fall+type@lti_consumer+block@abbe55d461984f40aa528cc2975e34ce/handler_noauth/outcome_service_handler HTTP/1.1
Authorization: OAuth oauth_consumer_key=“XXXXXXXX”,oauth_signature_method=“HMAC-SHA1”,oauth_timestamp=“1639383824”,oauth_nonce=“2364343909524145411638340190”,oauth_version=“1.0”,oauth_body_hash=“dP8BcBK7gueyGMO3rpFflGcg5T4%3D”,oauth_callback=“about%3Ablank”,oauth_signature=“aZJGf%2B1AprtdpgcXnOfaZkNd7MI%3D”
Content-Type: application/xml
User-Agent: PostmanRuntime/7.28.4
Accept: /
Host: learn.bssn.education
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 776
<?xml version="1.0" encoding="UTF-8"?>
<imsx_POXEnvelopeRequest xmlns=“http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0”>
<imsx_POXHeader>
<imsx_POXRequestHeaderInfo>
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>999999123</imsx_messageIdentifier>
</imsx_POXRequestHeaderInfo>
</imsx_POXHeader>
<imsx_POXBody>
course-v1%3AKIMO_U%2BTorque_101%2B2021_Fall:learn.bssn.education-abbe55d461984f40aa528cc2975e34ce:c3d8c56ed1758c725d06f39f023d2aac
en
0.92
</imsx_POXBody>
</imsx_POXEnvelopeRequest>
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 13 Dec 2021 08:23:44 GMT
Content-Type: application/xml; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Language, Origin, Cookie
Content-Language: en
X-Content-Type-Options: nosniff
P3P: CP=“Open edX does not have a P3P policy.”
Content-Encoding: gzip
<?xml version="1.0" encoding="UTF-8"?>
<imsx_POXEnvelopeResponse xmlns = “http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0”>
<imsx_POXHeader>
<imsx_POXResponseHeaderInfo>
<imsx_version>V1.0</imsx_version>
<imsx_messageIdentifier>999999123</imsx_messageIdentifier>
<imsx_statusInfo>
<imsx_codeMajor>success</imsx_codeMajor>
<imsx_severity>status</imsx_severity>
<imsx_description>Score for course-v1%3AKIMO_U%2BTorque_101%2B2021_Fall:learn.bssn.education-abbe55d461984f40aa528cc2975e34ce:c3d8c56ed1758c725d06f39f023d2aac is now 0.92</imsx_description>
<imsx_messageRefIdentifier>
</imsx_messageRefIdentifier>
</imsx_statusInfo>
</imsx_POXResponseHeaderInfo>
</imsx_POXHeader>
<imsx_POXBody></imsx_POXBody>
</imsx_POXEnvelopeResponse>
Code template for on-legged, server-to-server using OAuth1Session…
from requests_oauthlib import OAuth1Session
CONSUMER_KEY = "xxxxxxx"
CONSUMER_SECRET = "xxxxxxx"
ourSession = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET, force_include_body=True)
body= '<?xml version="1.0" encoding="UTF-8"?>' \
'<POXEnvelopeRequest xmlns="http://whateve">' \
'<POXHeader>' \
' <RequestHeaderInfo>' \
. . . .
' </RequestHeaderInfo>' \
'</POXHeader>' \
'</POXEnvelopeRequest>'
clen = str(len(body))
headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Host': 'X.Y.com',
'Content-Type': 'application/xml',
'Connection': 'keep-alive',
'Content-Length': clen
}
r = ourSession.post(url, headers=headers, data=body, verify=False)
# DEBUG: Comment out in and out as needed...
print("===================== B E G I N R E S P O N S E =======================\n")
print(r)
print(r.text)
print("===================== E N D of R E S P O N S E =======================\n")