As the title says, I’m wondering if it’s possible to integrate LinkedIn into our apps easily. Our client would like us to be able to do this, but we haven’t got any experience of using LinkedIn so have no idea where to being.
Searches for “Corona SDK LinkedIn” mainly gives results which are the other way round (i.e. putting your Corona skills onto your linkedin profile), or are simply pages which have a linkedin button on them. [import]uid: 84115 topic_id: 33868 reply_id: 333868[/import]
I’ve never used it before but there is a REST api that you should be able to use - https://developer.linkedin.com/rest [import]uid: 119420 topic_id: 33868 reply_id: 134618[/import]
I’ve never used it before but there is a REST api that you should be able to use - https://developer.linkedin.com/rest [import]uid: 119420 topic_id: 33868 reply_id: 134618[/import]
Not as simple as I’d hoped it would be.
I’ve never done anything using OAuth before so I’m not sure where I’m going wrong. I’ve set up an app on the website, and on the surface it seems like it is very similar to the Twitter API, so I thought I’d try amending the Twitter sample app and plugging in the LinkedIn key, secret, urls etc.
I get an error back when I try to login:
[html]
<title>Apache Tomcat/6.0.35 - Error report</title>
<style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style>
# HTTP Status 400 -
* * *
**type** Status report
**message** <u></u>
**description** <u>The request sent by the client was syntactically incorrect ().</u>
* * *
### Apache Tomcat/6.0.35
[/html]
I guess the" The request sent by the client was syntactically incorrect ()" is the main issue, but I’ve no idea why it’s syntactically incorrect.
Is there anyone at Corona with experience of OAuth and the Twitter sample who may be able to suggest a workaround? I guess it might be useful for other people in the future anyway, and if it can be quickly adapted from the Twitter app it could maybe go in with the other samples?
[import]uid: 84115 topic_id: 33868 reply_id: 139355[/import]
I’ve posted the same problem onto stackoverflow, and spotted a similar question (not specific to Corona, but having the same problems getting a request token):
http://stackoverflow.com/questions/1907111/linkedin-integration-establish-a-requesttoken
One of the replies (by VaibhaV) gives an example of what the HTTP string, header etc should look like. I’ve printed mine out, and they look the same (except different callback urls etc), so I’m even more confused.
Everything seems like it should work but it never has. I thought maybe the signature was being generated incorrectly, but the twitter example which also uses oauth works perfectly.
Here is the code I am using:
main.lua
--obviously the real app has the real details for these 2 variables
local consumer\_key = "My\_API\_Key\_from\_LinkedIn"
local consumer\_secret = "My\_Secret\_Key\_from\_LinkedIn"
local linkedin\_request = (oAuth.getRequestToken(consumer\_key, webURL,
"https://api.linkedin.com/uas/oauth/requestToken", consumer\_secret))
local linkedin\_request\_token = linkedin\_request.token
local linkedin\_request\_token\_secret = linkedin\_request.token\_secret
oAuth.lua
module(...,package.seeall)
local http = require("socket.http")
local ltn12 = require("ltn12")
local crypto = require("crypto")
local mime = require("mime")
-----------------------------------------------------------------------------------------
-- GET REQUEST TOKEN
-----------------------------------------------------------------------------------------
--
function getRequestToken(consumer\_key, token\_ready\_url, request\_token\_url, consumer\_secret)
local post\_data =
{
oauth\_consumer\_key = consumer\_key,
oauth\_timestamp = get\_timestamp(),
oauth\_version = '1.0',
oauth\_nonce = get\_nonce(),
oauth\_callback = token\_ready\_url,
oauth\_signature\_method = "HMAC-SHA1"
}
local post\_data = oAuthSign(request\_token\_url, "POST", post\_data, consumer\_secret)
local result = rawPostRequest(request\_token\_url, post\_data)
local token = result:match('oauth\_token=([^&]+)')
local token\_secret = result:match('oauth\_token\_secret=([^&]+)')
return
{
token = token,
token\_secret = token\_secret
}
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, "&")
print(query\_string\_except\_signature)
local sign\_base\_string = method .. '&' .. encode\_parameter(url) .. '&'
.. encode\_parameter(query\_string\_except\_signature)
local key = encode\_parameter(consumer\_secret) .. '&' .. encode\_parameter(token\_secret)
--print( "consumer\_secret key: " .. consumer\_secret ) -- \*\*debug
--print( "Encoded key: " .. key ) -- \*\*debug
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)
if method == "GET" then
return url .. "?" .. query\_string
else
return query\_string
end
end
-----------------------------------------------------------------------------------------
-- ENCODE PARAMETER (URL\_Encode)
-- Replaces unsafe URL characters with %hh (two hex characters)
-----------------------------------------------------------------------------------------
--
function encode\_parameter(str)
--return str
return str:gsub('[^-%.\_~a-zA-Z0-9]',function(c)
return string.format("%%%02x",c:byte()):upper()
end)--]]
end
-----------------------------------------------------------------------------------------
-- SHA 1
-----------------------------------------------------------------------------------------
--
function sha1(str,key,binary)
binary = binary or false
return crypto.hmac(crypto.sha1,str,key,binary)
end
-----------------------------------------------------------------------------------------
-- GET NONCE
-----------------------------------------------------------------------------------------
--
function get\_nonce()
return mime.b64(crypto.hmac(crypto.sha1,tostring(math.random()) .. "random"
.. tostring(os.time()),"keyyyy"))
end
-----------------------------------------------------------------------------------------
-- GET TIMESTAMP
-----------------------------------------------------------------------------------------
--
function get\_timestamp()
return tostring(os.time() + 1)
end
-----------------------------------------------------------------------------------------
-- RAW GET REQUEST
-----------------------------------------------------------------------------------------
--
function rawGetRequest(url)
local r,c,h
local response = {}
r,c,h = http.request
{
url = url,
sink = ltn12.sink.table(response)
}
return table.concat(response,"")
end
-----------------------------------------------------------------------------------------
-- RAW POST REQUEST
-----------------------------------------------------------------------------------------
--
function rawPostRequest(url, rawdata)
local r,c,h
local response = {}
print(url)
print(rawdata)
r,c,h = http.request
{
url = url,
method = "POST",
headers =
{
["Content-Type"] = "application/x-www-form-urlencoded",
["Content-Length"] = string.len(rawdata)
},
source = ltn12.source.string(rawdata),
sink = ltn12.sink.table(response)
}
return table.concat(response,"")
end
Main.lua also has some other stuff in there, but just the usual setting screen width / height variables etc , plus a button call to start the process. [import]uid: 84115 topic_id: 33868 reply_id: 139911[/import]
Not as simple as I’d hoped it would be.
I’ve never done anything using OAuth before so I’m not sure where I’m going wrong. I’ve set up an app on the website, and on the surface it seems like it is very similar to the Twitter API, so I thought I’d try amending the Twitter sample app and plugging in the LinkedIn key, secret, urls etc.
I get an error back when I try to login:
[html]
<title>Apache Tomcat/6.0.35 - Error report</title>
<style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style>
# HTTP Status 400 -
* * *
**type** Status report
**message** <u></u>
**description** <u>The request sent by the client was syntactically incorrect ().</u>
* * *
### Apache Tomcat/6.0.35
[/html]
I guess the" The request sent by the client was syntactically incorrect ()" is the main issue, but I’ve no idea why it’s syntactically incorrect.
Is there anyone at Corona with experience of OAuth and the Twitter sample who may be able to suggest a workaround? I guess it might be useful for other people in the future anyway, and if it can be quickly adapted from the Twitter app it could maybe go in with the other samples?
[import]uid: 84115 topic_id: 33868 reply_id: 139355[/import]
I’ve posted the same problem onto stackoverflow, and spotted a similar question (not specific to Corona, but having the same problems getting a request token):
http://stackoverflow.com/questions/1907111/linkedin-integration-establish-a-requesttoken
One of the replies (by VaibhaV) gives an example of what the HTTP string, header etc should look like. I’ve printed mine out, and they look the same (except different callback urls etc), so I’m even more confused.
Everything seems like it should work but it never has. I thought maybe the signature was being generated incorrectly, but the twitter example which also uses oauth works perfectly.
Here is the code I am using:
main.lua
--obviously the real app has the real details for these 2 variables
local consumer\_key = "My\_API\_Key\_from\_LinkedIn"
local consumer\_secret = "My\_Secret\_Key\_from\_LinkedIn"
local linkedin\_request = (oAuth.getRequestToken(consumer\_key, webURL,
"https://api.linkedin.com/uas/oauth/requestToken", consumer\_secret))
local linkedin\_request\_token = linkedin\_request.token
local linkedin\_request\_token\_secret = linkedin\_request.token\_secret
oAuth.lua
module(...,package.seeall)
local http = require("socket.http")
local ltn12 = require("ltn12")
local crypto = require("crypto")
local mime = require("mime")
-----------------------------------------------------------------------------------------
-- GET REQUEST TOKEN
-----------------------------------------------------------------------------------------
--
function getRequestToken(consumer\_key, token\_ready\_url, request\_token\_url, consumer\_secret)
local post\_data =
{
oauth\_consumer\_key = consumer\_key,
oauth\_timestamp = get\_timestamp(),
oauth\_version = '1.0',
oauth\_nonce = get\_nonce(),
oauth\_callback = token\_ready\_url,
oauth\_signature\_method = "HMAC-SHA1"
}
local post\_data = oAuthSign(request\_token\_url, "POST", post\_data, consumer\_secret)
local result = rawPostRequest(request\_token\_url, post\_data)
local token = result:match('oauth\_token=([^&]+)')
local token\_secret = result:match('oauth\_token\_secret=([^&]+)')
return
{
token = token,
token\_secret = token\_secret
}
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, "&")
print(query\_string\_except\_signature)
local sign\_base\_string = method .. '&' .. encode\_parameter(url) .. '&'
.. encode\_parameter(query\_string\_except\_signature)
local key = encode\_parameter(consumer\_secret) .. '&' .. encode\_parameter(token\_secret)
--print( "consumer\_secret key: " .. consumer\_secret ) -- \*\*debug
--print( "Encoded key: " .. key ) -- \*\*debug
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)
if method == "GET" then
return url .. "?" .. query\_string
else
return query\_string
end
end
-----------------------------------------------------------------------------------------
-- ENCODE PARAMETER (URL\_Encode)
-- Replaces unsafe URL characters with %hh (two hex characters)
-----------------------------------------------------------------------------------------
--
function encode\_parameter(str)
--return str
return str:gsub('[^-%.\_~a-zA-Z0-9]',function(c)
return string.format("%%%02x",c:byte()):upper()
end)--]]
end
-----------------------------------------------------------------------------------------
-- SHA 1
-----------------------------------------------------------------------------------------
--
function sha1(str,key,binary)
binary = binary or false
return crypto.hmac(crypto.sha1,str,key,binary)
end
-----------------------------------------------------------------------------------------
-- GET NONCE
-----------------------------------------------------------------------------------------
--
function get\_nonce()
return mime.b64(crypto.hmac(crypto.sha1,tostring(math.random()) .. "random"
.. tostring(os.time()),"keyyyy"))
end
-----------------------------------------------------------------------------------------
-- GET TIMESTAMP
-----------------------------------------------------------------------------------------
--
function get\_timestamp()
return tostring(os.time() + 1)
end
-----------------------------------------------------------------------------------------
-- RAW GET REQUEST
-----------------------------------------------------------------------------------------
--
function rawGetRequest(url)
local r,c,h
local response = {}
r,c,h = http.request
{
url = url,
sink = ltn12.sink.table(response)
}
return table.concat(response,"")
end
-----------------------------------------------------------------------------------------
-- RAW POST REQUEST
-----------------------------------------------------------------------------------------
--
function rawPostRequest(url, rawdata)
local r,c,h
local response = {}
print(url)
print(rawdata)
r,c,h = http.request
{
url = url,
method = "POST",
headers =
{
["Content-Type"] = "application/x-www-form-urlencoded",
["Content-Length"] = string.len(rawdata)
},
source = ltn12.source.string(rawdata),
sink = ltn12.sink.table(response)
}
return table.concat(response,"")
end
Main.lua also has some other stuff in there, but just the usual setting screen width / height variables etc , plus a button call to start the process. [import]uid: 84115 topic_id: 33868 reply_id: 139911[/import]
I’m updating this in the hope that someone (maybe someone from Ansca) might be able to help.
First of all, the good news. For some reason, using http.request did not work, but using network.request did work. I have no idea why since in both cases it used “POST” to request the requestToken and accessToken, and http.request works for the twitter example.
So the user can now authorise the app through LinkedIn, however after that I remain stuck. The ONLY task I want to be able to perform is to post a link to the users “shares” (think Facebook wall post), but have been unable to do it.
The problem I had is that I’m not sure exactly what the API requires me to send. It seems I have to resign each request using OAuth, but I’m not sure what details it requires when it generates the signature for a wall post request. I’m trying to send the data using JSON format, which the API docs says is acceptable. However I don’t know whether I need to convert it to JSON before signing the request, or use a table to sign and then convert to JSON. I seem to have tried everything with no luck, but I suspect it’s because I’m not familiar enough with exactly how OAuth works.
I get responses such as this:
RESPONSE: {
"errorCode": 0,
"message": "[unauthorized]. OAU:my\_Linkedin\_key|76f9479a-f7b6-4168-8786-a943f34be230|\*01|\*01:1359453939:JLRu91N9RGs+tgNr99ULX8NtY80=",
"requestId": "JY76TXOD7U",
"status": 401,
"timestamp": 1359453938450
}
I don’t see why it would be unauthorised, since the signing process was valid when requesting the requestToken and accessToken?
If anyone out there is able to help, I’ll then be able to tidy up my code and provide it for everyone else to use in future. [import]uid: 84115 topic_id: 33868 reply_id: 140740[/import]
I’m updating this in the hope that someone (maybe someone from Ansca) might be able to help.
First of all, the good news. For some reason, using http.request did not work, but using network.request did work. I have no idea why since in both cases it used “POST” to request the requestToken and accessToken, and http.request works for the twitter example.
So the user can now authorise the app through LinkedIn, however after that I remain stuck. The ONLY task I want to be able to perform is to post a link to the users “shares” (think Facebook wall post), but have been unable to do it.
The problem I had is that I’m not sure exactly what the API requires me to send. It seems I have to resign each request using OAuth, but I’m not sure what details it requires when it generates the signature for a wall post request. I’m trying to send the data using JSON format, which the API docs says is acceptable. However I don’t know whether I need to convert it to JSON before signing the request, or use a table to sign and then convert to JSON. I seem to have tried everything with no luck, but I suspect it’s because I’m not familiar enough with exactly how OAuth works.
I get responses such as this:
RESPONSE: {
"errorCode": 0,
"message": "[unauthorized]. OAU:my\_Linkedin\_key|76f9479a-f7b6-4168-8786-a943f34be230|\*01|\*01:1359453939:JLRu91N9RGs+tgNr99ULX8NtY80=",
"requestId": "JY76TXOD7U",
"status": 401,
"timestamp": 1359453938450
}
I don’t see why it would be unauthorised, since the signing process was valid when requesting the requestToken and accessToken?
If anyone out there is able to help, I’ll then be able to tidy up my code and provide it for everyone else to use in future. [import]uid: 84115 topic_id: 33868 reply_id: 140740[/import]
In case anyone was interested, I managed to get this to work eventually.
I’ve put a sample onto the code exchange, it’s based on the twitter sample so anyone who has used that should be able to follow it pretty easily.
http://developer.coronalabs.com/code/basic-linkedin-integration
In case anyone was interested, I managed to get this to work eventually.
I’ve put a sample onto the code exchange, it’s based on the twitter sample so anyone who has used that should be able to follow it pretty easily.
http://developer.coronalabs.com/code/basic-linkedin-integration