ColdFusion and OAuth Part 2 - LinkedIn

This post is more than 2 years old.

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.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Tony Junkes posted on 4/4/2013 at 2:18 AM

I'm thinking your title should say LinkedIn and not Facebook right? Since this covers LI.

Comment 2 by Raymond Camden posted on 4/4/2013 at 4:26 AM

Doh! Too late for the URL, but fixed. Thank you.

Comment 3 by Chris Pilie posted on 4/8/2013 at 7:21 PM

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!

Comment 4 by Tomasz Mieczkowski posted on 4/22/2013 at 7:10 PM

Raymond - you are a god!
You really saved me hours of work with this post.
I owe you a large beer!

Comment 5 by Raymond Camden posted on 4/22/2013 at 7:27 PM

Warning - I'm a beer snob. ;)

Comment 6 by Mustafa Abusalah posted on 4/23/2013 at 8:57 AM

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

Comment 7 by Raymond Camden posted on 4/23/2013 at 3:09 PM

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

Comment 8 by Mustafa Abusalah posted on 4/24/2013 at 9:49 AM

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...

Comment 9 by Raymond Camden posted on 4/24/2013 at 2:45 PM

As I work for Adobe, I don't normally test on Railo. ;)

Comment 10 by Paul Mascari posted on 4/26/2013 at 8:10 PM

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)

Comment 11 by Raymond Camden posted on 4/26/2013 at 11:02 PM

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.

Comment 12 by richfergus posted on 11/17/2013 at 12:15 AM

Thank you.....

Comment 13 by Misty posted on 4/9/2014 at 8:57 PM

Can it be Used with ColdFusion version 9.0.0

not 9.0.1

Comment 14 by Raymond Camden posted on 4/9/2014 at 11:14 PM

Um, maybe? :) Try it and see.

Comment 15 by Misty posted on 4/10/2014 at 11:01 PM

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

Comment 16 by Raymond Camden posted on 4/11/2014 at 1:03 AM

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

Comment 17 by Misty posted on 4/20/2014 at 11:14 AM

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.

Comment 18 by Misty posted on 4/20/2014 at 11:15 AM

I am using the ID in the option value's

Comment 19 by Raymond Camden posted on 4/21/2014 at 5:28 PM

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.

Comment 20 by Misty posted on 4/21/2014 at 10:11 PM

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

Comment 21 by Misty posted on 4/24/2014 at 6:20 PM

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...

Comment 22 by Raymond Camden posted on 4/24/2014 at 6:41 PM

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.

Comment 23 by Misty posted on 4/24/2014 at 8:30 PM

Thanks ray, BTW i have already posted on Linkedin Forums,

Comment 24 by Misty posted on 4/30/2014 at 12:26 PM

Ray, In developer API, we see often the auth1.0 redirect, do we need to fill that info or not.

Comment 25 by Raymond Camden posted on 4/30/2014 at 4:26 PM

Typically the caller sends that.

Comment 26 by Misty posted on 5/23/2014 at 11:02 PM

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>

Comment 27 by Raymond Camden posted on 5/23/2014 at 11:05 PM

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.

Comment 28 by Raymond Camden posted on 5/23/2014 at 11:06 PM

Ahah, if you look here, https://developer.linkedin...., go to Defaults, and you will see ID is *not* listed there.

Comment 29 by Misty posted on 5/24/2014 at 9:22 AM

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.

Comment 30 by Raymond Camden posted on 5/24/2014 at 5:42 PM

I assume you mean "always coming, but sometimes", as just sometimes. The best I can suggest now is to try LI's tech support.

Comment 31 by knowledgenotebook posted on 3/3/2016 at 4:34 PM

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