How to use the 'lis_outcome_service_url' and 'lis_result_sourcedid' to issue a simple grade posting

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")