Earlier this week I discussed how to integrate ColdFusion and Facebook using OAuth2. I mentioned that this was part of a set of examples I had done involving Facebook, LinkedIn, and Google. In today's entry, I'm going to discuss the LinkedIn API.
Luckily, or I should say, obviously, since this is also an OAuth2 protocol, the code is almost the exact same. I literally took the Facebook demo, copied it over, and used that as a starting point. Like Facebook, LinkedIn has a developer portal (developer.linkedin.com) that includes documentation as well as a place to register applications. This may be a point of confusion for some. You may be thinking, "I'm not building an app, I just want to hook up with LinkedIn", but in general, both Facebook and LinkedIn treat these "applications" as a way to define your connection from your site to its own data.
Finding the place to add application is a bit weird. Once at the developer portal and logged in, notice you can click a down arrow next to your name in the upper right corner:

Click it, and then select API Keys.

On the next page click "Add New Application". The form here is somewhat intimidating. LinkedIn really could do a better job here, especially with using some defaults since I shouldn't have to re-enter the same data every time. I'd just bother with the required fields. Once set up, you'll want to make note of your OAuth keys. All you care about is the API Key and Secret Key:

Now we can switch to the code. As before, the process is as follows: Present a link. User goes to LinkedIn. User is sent back with secret tokens of goodness. We get another token. Then we have the power to make API calls. (As a reminder, both this and the previous demo were written for ColdFusion 8. Hence the tag-based components.)
First, the Application.cfc - almost an exact mirror of the Facebook code.
Next, the index.cfm code. Again, I'm presenting a link I assume my user will click. This is based on checking for a session variable that will be defined once the user finishes the OAuth process.
As before, our links contains part of our access data, a list of permissions, as well as a URL stating where the user is sent back to. Probably the only interesting thing here is scope. That reflects the permissions and will change the prompt the user sees. You will want to modify this based on your needs.
Once the link is clicked, the user will see something like this:

Now let's look at redir.cfm. Again, this is virtually identical to the Facebook code, excepting that their result for the access token is nicely formatted in JSON as opposed to being a string you have to parse manually.
If everything works out, the user is sent back to the index.cfm page. If you remember, I called a LinkedIn component that is initialized with my access token. I built three methods for this CFC: one to get user data, one to get friends, and one to send messages. To be clear, their API supports more, but this is all my buddy wanted so that's all I built. Here's the component.
Enjoy. Let me know if you have any questions. Tomorrow I'll write up the third entry in the series. That entry will discuss how to authenticate users with Google.
Archived Comments
I'm thinking your title should say LinkedIn and not Facebook right? Since this covers LI.
Doh! Too late for the URL, but fixed. Thank you.
Great post! Just a little recap of some trouble I had for anyone trying this. I did get an error coming back from linkedin. It seems to be in a weird place tho.
"Element ACCESS_TOKEN is undefined in RES."
So I dumped the "res" within the redirect file and this is what I got.
"missing required parameters, includes an invalid parameter value, parameter more then once. : Unable to retrieve access token : appId or redirect uri does not match authorization code or authorization code expired"
I check the "liAccessTokenURL" and the secret and the apikey do match so my head hurts from scratching it.
Then! I used the force and discovered with Ray's help that my redirect urls did not match. The link on the redir.cfm had a "www" and the other with the link did not have the "www". Thanks Ray!
Raymond - you are a god!
You really saved me hours of work with this post.
I owe you a large beer!
Warning - I'm a beer snob. ;)
Hi Raymond,
I'm trying to call the below url with specific profile fields:
https://api.linkedin.com/v1...
When I make the call directly from the browser it works fine, but if I call it using cfhttp request I got 404 Not Found error.
The issue is most likely related to url encoding, kindly advise how send the request using cfhttp or another method without being enforced to be urlencoded
I tried this and it worked for me in CF10:
<cfhttp url="https://api.linkedin.com/v1...">
<cfhttpparam type="header" name="x-li-format" value="json">
</cfhttp>
<cfdump var="#cfhttp#">
I'm using Railo, open source CFM and it did not work. I found an alternative method to cfhttp on the below link and it worked: http://coldfusion9.blogspot...
As I work for Adobe, I don't normally test on Railo. ;)
Thanks a million for the post, Ray. I had been wrestling with this API for hours. Question regarding the call to LI for the AccessToken....
I was pulling my hair out wondering why I couldn't get past this step. Was constantly getting this error from LI: "Unable to retrieve access token : appId or redirect uri does not match authorization code or authorization code expired"
Any idea why my original CFHTTP call, seen below, would produce an unacceptable call as opposed to your drop-dead-simple <cfhttp url="#liAccessTokenURL#"> ???
<cfhttp url="https://www.linkedin.com/ua..."
method="get"
result="linkinToken">
(I had also tried method="post" as the LI documentation states to no avail)
Um, you got me. I assume you have confirmed your redirecturi matches? Note that you want to ensure that if you included www, you include it everywhere.
Thank you.....
Can it be Used with ColdFusion version 9.0.0
not 9.0.1
Um, maybe? :) Try it and see.
Hi ray, Well it worked..
Got a question, running above code only gives me the firstname, lastname, title if any and the status..
How can i get additional details like emailaddress, and otehr relevant fields like education etc of a user and the connections profiles
As with my other examples, it is based on the SCOPE value. That SCOPE value tells LinkedIn what your app wants to use, and then LI will tell the user, "Hey, this app wants X, Y, and Z, are you cool with that?"
thanks, got it and finaaly i run it, question on how to send message to friends as the list of friends coming as structures within arrays, need to use their name or what?
trying like this, i am right, the recipeints will have the ID or need to pass something else
<cfset friends = session.liAPI.getFriends()>
<cfset theMessagePos = friends.values>
<cfsavecontent variable="getlstfriends">
<select name="friendsList" id="friendsList">
<cfloop from="1" to="#ArrayLen(theMessagePos)#" index="k">
<cfoutput>
<cfif theMessagePos[k].firstname contains 'private' AND theMessagePos[k].lastname contains 'private'
AND theMessagePos[k].ID contains 'private'>
<!--- Do Nothing --->
<cfelse>
<option value="#theMessagePos[k].id#">#theMessagePos[k].firstname# #theMessagePos[k].lastname#</option>
</cfif>
</cfoutput>
</cfloop>
</select>
</cfsavecontent>
<cfoutput>#getlstfriends#</cfoutput>
as per api, i am seeing this:
recipients mailbox-item yes Containing element for one or more recipient elements.
recipient recipients at least one An intended recipient of the message who is directly connected to the poster.
I am using the ID in the option value's
I have not looked at the API yet for sending messages. It looks like you have. I'm not sure what you are asking though. If you know the API, then just use it.
Hi ray, Working on it, But i am checking if i need to pass an ID ot the name to the api so the message can be sent to the user
Hi ray, I Passed the Code as the ID of the user to the function sendMessage
but i am getting 403, Method not allowed:
here is the screenshot:
http://screencast.com/t/XVY...
Misty, at this point, your request is really OT for this particular post. It sounds like you need to post to FB's support forums, or Stack Overflow.
Thanks ray, BTW i have already posted on Linkedin Forums,
Ray, In developer API, we see often the auth1.0 redirect, do we need to fill that info or not.
Typically the caller sends that.
Hi Ray,
Element ID is undefined in ME
The following throws error sometimes, not everytime, any idea?
<cfset session.liAPI = createObject("component","services.linkedin").init(session.liaccesstoken)>
<cfset me = session.liAPI.getMe()>
<cfset session.Linkedmyid = me.id>
<cfset session.linkinMyName = me.firstname & " " & me.lastname>
I don't know. Maybe LI doesn't always return it? Best I can recommend is checking for the existence of it before copying it.
Ahah, if you look here, https://developer.linkedin...., go to Defaults, and you will see ID is *not* listed there.
Thanks ray,
As per Docs, I have requested additional fields through this:
<cfhttp url="https://api.linkedin.com/v1..." result="httpResult">
The Error is always coming, but sometimes.
I assume you mean "always coming, but sometimes", as just sometimes. The best I can suggest now is to try LI's tech support.
I wonder if anyone has tried this method of authentication with LNK api recently.
I just tried it. (btw, I'm on LNK developer platform, so, I have my own key etc., my developer Setting is: development).
Since r_network parameter is not available from my LNK developer account, I removed it from the liURL var.
Here's what I got in debugging mode, question, why "Access to connections denied"? Is the r_network parameter required to get connections' data? It seems so, thoughts? Thanks.
This is a LI user.
friends
Struct
errorCode number 0
message string Access to connections denied
requestId string TPZDNCxxxx
status number 403