LinkedIn API in a Grails Application

Before getting started, I want to mention that the LinkedIn API has a major limitation that may change your design. My client’s website has a public facing form where a user can apply for job openings and upload their resume. We wanted to add an option for them to log in with LinkedIn to speed up the application process. Originally, I was simply going to capture and store the user’s public profile url. Then, I was planning to call the LinkedIn API to get some of their public profile data and display it on a screen in our application in real time.

My plans had to change when I discovered that a LinkedIn user would have to log in each time we wanted to pull the data from their public profile. In other words, every time you hit the LinkedIn API to access the public profile data (yes, the data you can see by going to a person’s public url, or simply Googling for their LinkedIn profile), the LinkedIn user must log in (Ref: http://developer.linkedin.com/thread/1418). My alternative solution was to capture their public profile data in our database. It is useful for our system to store the profile information for searching purposes, even though the data could be outdated. Each time a user logs in through the LinkedIn API, it will re-upload their profile data and refresh our database.

Getting the LinkedIn API working in a Grails application isn’t difficult. First you’ll need to create a LinkedIn Developer account (http://developer.linkedin.com), and for that, you’ll need a LinkedIn account. Once you’re signed into the LinkedIn DeveloperNetwork, follow the instruction to add a new application. This will generate the unique API key and secret key you will need.

LinkedIn uses Oauth for authentication, so the next step is to set this up. The good news is, there’s a Grails plugin for that… but it requires some tweaking (I’ll get to that soon). Install the oauth-plugin in your Grails app… http://grails.org/plugin/oauth

To configure oauth, add this code to the Config.groovy file…

oauth {
linkedin {
requestTokenUrl="https://api.linkedin.com/uas/oauth/requestToken"
accessTokenUrl="https://api.linkedin.com/uas/oauth/accessToken"
authUrl="https://api.linkedin.com/uas/oauth/authorize"
consumer.key="###"
consumer.secret="###"
}
}

(Note: The consumer.key and consumer.secret are unique to each site. Replace the ‘###’ value with the unique values generated by LinkedIn for your application. consumer.key = API key; consumer.secret = Secret Key)

Now for the tweaking. As of this writing the version of the oauth-plugin is 0.12, which contains a bug. The workaround for this bug is described in the plugin documentation. Here’s the code you’ll need to add in the Config.groovy file for the workaround…

//necessary to fix a bug in the Oauth plugin 0.12
httpClient {
timeout {
socket = 5000
connection = 5000
}
}

Next, you’ll want to add a link on your page so your user can log in to LinkedIn…

<g:oauthLink consumer='linkedin' returnTo="[controller:'jobPosting', action: 'linkedin', project:search?.id ]">
Login with LinkedIn
</g:oauthLink>

Here I added an action in my existing JobPostingController rather than using the controller that came with the plugin…

class JobPostingController {
def oauthService
def apiUrl = "http://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url,headline,summary)"
def linkedin = {
if (session.oauthToken == null) {
redirect(uri:"/")
}
if (params?.apiUrl) apiUrl = params.apiUrl
def response = oauthService.accessResource(
apiUrl, 'linkedin', [key:session.oauthToken.key, secret:session.oauthToken.secret], 'GET')
//LinkedInProfile is a domain class created to store the data in our application
LinkedInProfile linkedInProfile = new LinkedInProfile()
if(response) {
def person = new XmlParser().parseText(response.body)
linkedInProfile.firstName = person.get("first-name")[0]?.text()
linkedInProfile.lastName = person.get("last-name")[0]?.text()
//...continue parsing XML
}
render(view: 'thankYou')
}
}

This code will handle the LinkedIn authentication, and then parse the XML in the response. The apiUrl value can be changed to retrieve specific data, or LinkedIn provides a default (https://developer.linkedin.com/documents/profile-fields).

One other thing I wanted to touch on. When the user chooses to login through LinkedIn, they will be redirected to a LinkedIn authorization page. This means you’ll lose your params data. In my case, I needed to pass the job id back to my page after the LinkedIn authentication was completed. This was easy once I determined how it was working. All I needed to do was override the default oauthUrl tag in the OauthTagLib with a new TagLib in our application. Now I can pass any params back to my page that I need to.

References:
http://java.dzone.com/articles/grails-oauth-and-linkedin-apis (a bit outdated, but a good tutorial using the basic plugin code)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*