Unable to post to LinkedIn “shares” using OAuth, after successfully authorizing the user's login

After originally struggling to get a request and access token, I finally now get those from LinkedIn successfully. However, the only thing I want to be able to do is let users post links to their “shares”, and I have had no luck getting this to work.

After the user has signed in successfully I do the following:

 share\_object = {  
 comment = "Testing out the LinkedIn Share API with JSON",  
 content = {  
 title = "Test post to LinkedIn",  
 submitted\_url = "http://www.somewebsite.com",  
 submitted\_image\_url = "http://www.somewebsite.com/image.png"  
 },  
 visibility = {  
 code = "anyone"  
 }  
 }  
 share\_object = json.encode(share\_object)  
  
 local params = {}  
 params[1] =  
 {  
 key = 'share',  
 value = share\_object  
 }  
  
 request\_response = oAuth.makeRequest("http://api.linkedin.com/v1/people/~/shares?format=json", params, consumer\_key, access\_token, consumer\_secret, access\_token\_secret, "POST")  
  

I have printed out the consumer_key, access_token, consumer_secret and access_token_secret after they are received and they are all correct (i.e. they match the tokens and secrets when I log into my LinkedIn app).

This is the function that the “request_response = oAuth.makeRequest” calls from the oAuth class:

 ----------------------------------------------------------------------------------------  
 -- MAKE REQUEST  
 ----------------------------------------------------------------------------------------  
 function makeRequest(url, body, consumer\_key, acc\_token, consumer\_secret, acc\_token\_secret, method)  
  
  
 local post\_data =   
 {  
 oauth\_consumer\_key = consumer\_key,  
 oauth\_timestamp = get\_timestamp(),  
 oauth\_version = '1.0',  
 oauth\_nonce = get\_nonce(),  
 oauth\_token = acc\_token,  
 oauth\_token\_secret = acc\_token\_secret,  
 oauth\_signature\_method = "HMAC-SHA1",   
 }  
  
 for i=1, #body do  
 post\_data[body[i].key] = body[i].value  
 end  
  
 local post\_data = oAuthSign(url, method, post\_data, consumer\_secret)  
  
 result = rawPostRequest(url, post\_data)  
  
 print(result)  
 return result  
 end  
 -----------------------------------------------------------------------------------------  
 -- OAUTH SIGN  
 -----------------------------------------------------------------------------------------  
 --  
 function oAuthSign(url, method, args, consumer\_secret)  
   
 local token\_secret = args.oauth\_token\_secret or ""  
  
 args.oauth\_token\_secret = nil  
  
 local keys\_and\_values = {}  
  
 for key, val in pairs(args) do  
 table.insert(keys\_and\_values,   
 {  
 key = encode\_parameter(key),  
 val = encode\_parameter(val)  
 })  
 end  
  
 table.sort(keys\_and\_values, function(a,b)  
 if a.key \< b.key then  
 return true  
 elseif a.key \> b.key then  
 return false  
 else  
 return a.val \< b.val  
 end  
 end)  
  
 local key\_value\_pairs = {}  
  
 for \_, rec in pairs(keys\_and\_values) do  
 table.insert(key\_value\_pairs, rec.key .. "=" .. rec.val)  
 end  
  
 local query\_string\_except\_signature = table.concat(key\_value\_pairs, "&")  
  
 local sign\_base\_string = method .. '&' .. encode\_parameter(url) .. '&'  
 .. encode\_parameter(query\_string\_except\_signature)  
  
 local key = encode\_parameter(consumer\_secret) .. '&' .. encode\_parameter(token\_secret)  
 local hmac\_binary = sha1(sign\_base\_string, key, true)  
  
 local hmac\_b64 = mime.b64(hmac\_binary)  
 local query\_string = query\_string\_except\_signature .. '&oauth\_signature=' .. encode\_parameter(hmac\_b64)  
  
 signature = encode\_parameter(hmac\_b64)  
 local authRealm = "http://api.linkedin.com"  
  
 --store headers to use as http header "Authorization"  
 oauth\_headers = { ([[OAuth realm="%s"]]):format(authRealm or "") }  
 for k,v in pairs(args) do  
 if k:match("^oauth\_") then  
 table.insert(oauth\_headers, k .. "=\"" .. encode\_parameter(v) .. "\"")  
 end  
 end  
 table.insert(oauth\_headers, "oauth\_signature=\"" .. signature .. "\"")  
  
 oauth\_headers = table.concat(oauth\_headers, ", ")  
  
 if method == "GET" then  
 return url .. "?" .. query\_string  
 else  
 return query\_string  
 end  
 end  
  
 ----------------------------------------------------------------------------------------  
 -- RAW POST REQUEST  
 ----------------------------------------------------------------------------------------  
 function rawPostRequest(url, rawdata)  
   
 local r,c,h  
 local response = {}  
   
 r,c,h = http.request  
 {  
 url = url,  
 method = "POST",  
 headers =   
 {  
 ["Authorization"] = oauth\_headers,  
 ['x-li-format'] = "json",  
 ["Content-Type"] = "application/json",  
 },  
 source = ltn12.source.string(rawdata),  
 sink = ltn12.sink.table(response)  
 }  
   
 return table.concat(response,"")  
 end  

The error message returned is:

Response: {
“errorCode”: 0,
“message”: “[unauthorized]. OAU:my_API _Key|my_OAuth_User_Token |*01|*01:1360586673:+ZAEOLZ+jckeUr26T4EES4sC+1g=”,
“requestId”: “HWN64K6G4R”,
“status”: 401,
“timestamp”: 1360586673371
}

(the “my_API _Key” and “my_OAuth_User_Token” fields have the actual data in the response).

I have no idea why it is unauthorized if I signed the request using all of the correct tokens and secrets.

We’re absolutely stuck now and this is the last thing we need to finish our app.
Is there anyone out there who can help? [import]uid: 84115 topic_id: 35791 reply_id: 335791[/import]

I have also checked to see if I am possibly generating an incorrect signature, by checking it against the LinkedIn Test Console - http://developer.linkedin.com/oauth-test-console

I tested using http://api.linkedin.com/v1/people/~ as the url and a fixed nonce + timestamp. The generated signature in my app was exactly the same as in the test console, however I still receive a 401 unauthorized response. So I have even less idea on what the cause of the problem could be :frowning: [import]uid: 84115 topic_id: 35791 reply_id: 142370[/import]

Having fiddled around with some other stuff, I now have a different 400 error:

“message”: “Couldn’t parse share document: error: Unexpected end of file after null”,

To do this I changed my URL to “http://api.linkedin.com/v1/people/~/shares” and changed the postdata table in my makeRequest function to

local post\_data =   
 {  
 oauth\_consumer\_key = consumer\_key,  
 oauth\_timestamp = get\_timestamp(),  
 oauth\_version = '1.0',  
 oauth\_nonce = get\_nonce(),  
 oauth\_token = acc\_token,  
 oauth\_token\_secret = acc\_token\_secret,  
 oauth\_signature\_method = "HMAC-SHA1",   
 format = "json",  
 share = body   
 }  
  

where “body” is the json encoded table “share_object” from my very first post.

Now, because it still does not work, I had no way of knowing if my change was an improvement - errors are errors in my eyes.
However, after getting this new error numerous times I suddenly got another new error telling me that my throttle limits for this type of request had been reached. LinkedIn only lets a user perform certain actions a fixed number of times, so it would seem that my request to post a share is reaching them in an authorised state, but the “Couldn’t parse share document: error: Unexpected end of file after null” means that no “share” data is reaching them.

So I decided to use Wireshark to check the traffic. I noticed that although I have set:

  
['x-li-format'] = "json",  
["Content-Type"] = "application/json"  
  

in the traffic data it says the Content-Type is “application/x-www-form-urlencoded\r\n”.

Why would it be changing to application/x-www-form-urlencoded? I definitely haven’t set it to do that anywhere else by mistake, at the point of the request the Content-Type is definitely “application/json” (I have also tried “application/json;charset=utf-8” to see if that made any difference).

I’m not an expert on POST requests, so if anyone has any useful info it would be appreciated. [import]uid: 84115 topic_id: 35791 reply_id: 142401[/import]

I have also checked to see if I am possibly generating an incorrect signature, by checking it against the LinkedIn Test Console - http://developer.linkedin.com/oauth-test-console

I tested using http://api.linkedin.com/v1/people/~ as the url and a fixed nonce + timestamp. The generated signature in my app was exactly the same as in the test console, however I still receive a 401 unauthorized response. So I have even less idea on what the cause of the problem could be :frowning: [import]uid: 84115 topic_id: 35791 reply_id: 142370[/import]

Having fiddled around with some other stuff, I now have a different 400 error:

“message”: “Couldn’t parse share document: error: Unexpected end of file after null”,

To do this I changed my URL to “http://api.linkedin.com/v1/people/~/shares” and changed the postdata table in my makeRequest function to

local post\_data =   
 {  
 oauth\_consumer\_key = consumer\_key,  
 oauth\_timestamp = get\_timestamp(),  
 oauth\_version = '1.0',  
 oauth\_nonce = get\_nonce(),  
 oauth\_token = acc\_token,  
 oauth\_token\_secret = acc\_token\_secret,  
 oauth\_signature\_method = "HMAC-SHA1",   
 format = "json",  
 share = body   
 }  
  

where “body” is the json encoded table “share_object” from my very first post.

Now, because it still does not work, I had no way of knowing if my change was an improvement - errors are errors in my eyes.
However, after getting this new error numerous times I suddenly got another new error telling me that my throttle limits for this type of request had been reached. LinkedIn only lets a user perform certain actions a fixed number of times, so it would seem that my request to post a share is reaching them in an authorised state, but the “Couldn’t parse share document: error: Unexpected end of file after null” means that no “share” data is reaching them.

So I decided to use Wireshark to check the traffic. I noticed that although I have set:

  
['x-li-format'] = "json",  
["Content-Type"] = "application/json"  
  

in the traffic data it says the Content-Type is “application/x-www-form-urlencoded\r\n”.

Why would it be changing to application/x-www-form-urlencoded? I definitely haven’t set it to do that anywhere else by mistake, at the point of the request the Content-Type is definitely “application/json” (I have also tried “application/json;charset=utf-8” to see if that made any difference).

I’m not an expert on POST requests, so if anyone has any useful info it would be appreciated. [import]uid: 84115 topic_id: 35791 reply_id: 142401[/import]