Saturday, April 23, 2016

Retrieving User Profile Information from LinkedIn using OAuth 2.0 Authorization Code Grant Type

In our day to day interactions on internet, we come across with lots of websites where we have to create accounts to use the website for our work. If you need to purchase stuff online, you may create an account on Amazon or Ebay, for using a taxi you may create an account on Uber, for internet messaging or voice calls you may create an account on Viber or Whatsapp and this goes on and on where you end up with having so many accounts created for you on internet. If you use different credentials for different accounts, it becomes worse where you have to remember all your usernames and passwords for each website.

In order to address this issue, modern websites make use of the OAuth protocol [1] with the concepts of “Identity Federation” and “Delegated Authorization”. For example, the website you need to create an account may provide the facility to login with an existing account in a different Identity Provider such as Facebook, Twitter or LinkedIn so you don’t need to create a new account and also remember your credentials. In some cases, the website will ask you to fill out a lengthy form with all your personal details, but it will provide the feature to retrieve these data from your linkedIn or facebook account. In such case, you simply login to your facebook or LinkedIn account and authorize that website to access your personal information. Then the website will retrieve your profile details and fill out the form for you so you do not need to enter all your details when registering the account.

If you try to purchase a book from Oreilly, it will ask you to login to the Oreilly website.  But if you do not already have an account, you need to fill out this form to create an account.


However if you are lazy to fill these information and create the account, Oreilly provides the facility to login with your LinkedIn, Google+, Facebook or Twitter account so you don’t need to fill out that form and create an account for you.

If you try to login with your LinkedIn account, then LinkedIn will ask you to authorize this action. We call this as the “User Consent” in OAuth terminology.

LinkedIn will tell you what data Oreilly will be able to access from your LinkedIn account and what actions that Oreilly will be able to perform on your LinkedIn account on behalf of you.
The good thing here is that you enter your LinedIn account credentials to LinkedIn itself so you don’t need to be worried as Oreilly does not see your credentials. Once you authenticate successfully with LinkedIn and “Allow access”, Oreilly will be able to request your email address (which you have provided to LinkedIn) and your profile details from LinkedIn. This way Oreilly can identify you as a valid user and will consider you as an authenticated user to Oreilly website.

So this is what basically an end user would experience. Let’s take a look at how this is made possible with the OAuth 2.0 protocol. You can refer LinkedIn’s documentation [2] for more information. 


OAuth Oreilly sample(1).png
Above diagram explains all the associated steps in this which is the Authorization Code grant type in OAuth 2.0.

You also can develop your own web applications that makes use of OAuth capabilities and facilitate users to use their existing internet identities in your website. In this blog post I am providing you the steps to try this out with LinkedIn as the Identity Provider. Even if you use facebook, twitter, google+ or any other identity provider, the steps would be similar and you can refer the documentation of the identity provider to get to know more on how to implement this capability.


Step 1 — Configuring your LinkedIn application

When our client web application needs to retrieve the user profile details of a LinkedIn user using the APIs of LinkedIn, LinkedIn should be able to identify the validity of the request made by the client web application. In order to do that, we need to register our web client application on LinkedIn by creating an OAuth application in LinkedIn developer account.

Go to https://www.linkedin.com/secure/developer?newapp= and create an application.



Then we have to fill this form providing details of the web application which is the consumer of the APIs of LinkedIn. 


Once we create the application, LinkedIn will give us the “Client ID” and the “Client Secret” for the application.

In the settings, we need to define what are the permissions required by this client application. In this example, we need to access the LinkedIn user’s profile information and the email address. For that, we need to grant r_basicprofile and r_emailaddress permissions. These are called as scopes in OAuth terminology. We also need to provide the callback URL of our client web application where LinkedIn will send the responses to that URL. If you are writing a java web application, this can be a servlet in the application which can read the response sent by LinkedIn and process it.

You can get to know more details of the LinkedIn permissions of the basic-profile from [3]. .

Following are the scopes and the fields of the user profile that we will use in our client application. You can add more scopes and their information fields as per your requirements.

Scope : r_emailaddress
Field Name
Description
email-address
The LinkedIn member's primary email address.  Secondary email addresses associated with the member are not available via the API.


Scope : r_basicprofile
Field Name
Description
id
A unique identifying value for the member.

This value is linked to your specific application.  Any attempts to use it with a different application will result in a "404 - Invalid member id" error.
first-name
The member's first name.
last-name
The member's last name.
industry
The industry the member belongs to.
picture-url
A URL to the member's formatted profile picture, if one has been provided.
public-profile-url
The URL to the member's public profile on LinkedIn.
headline
The member's headline.

In the settings of the application, the “Application Status” decides the visibility of this application. In the “Development” state, only the linkedin users defined under the “Roles” section will be able to authorize the client and let it access linkedin profile details. This is sufficient until you finish the testing of the application before going live.



Now we are all set for consuming LinkedIn APIs in our client application.


Step 2 — Request an Authorization Code

In this step, our client web application needs to send a request to the OAuth authorization endpoint of LinkedIn.

For that we need to send a GET request to https://www.linkedin.com/uas/oauth2/authorization with the following parameters.  The parameter values should be URL encoded which is a requirement according to the OAuth 2.0 specification.

Parameter
Description
Required
response_type
The value of this field should always be: code
Yes
client_id
The "API Key" value generated when you registered your application.
Yes
redirect_uri
Yes
state
Yes
scope
A URL-encoded, space delimited list of member permissions your application is requesting on behalf of the user. If you do not specify a scope in your call, we will fall back to using the default member permissions you defined in your application configuration.
e.g. scope=r_fullprofile%20r_emailaddress%20w_share
Optional


Sample Values for the request would be as following. When you are trying out this, you need to use the client_id value which you obtained when registering the client application in LinkedIn and as the redirect_uri, the callback URL of your client web application. “state” is a random generated number.  


Parameter
Sample Value
URL Encoded Value
response_type
code
code
client_id
75kkcu5le8hca0
75kkcu5le8hca0
redirect_uri
http://localhost:8080/mylinkedinoauthapp/callback
http%3A%2F%2Flocalhost%3A8080%2Fmylinkedinoauthapp%2Fcallback
state
123456
123456
scope
r_basicprofile r_emailaddress
r_basicprofile%20r_emailaddress


Adding above parameters to the request, the sample URL would look like below.


For trying this out, you can simply prepare the URL with your values and paste it in a browser. It will take you to LinkedIn and the user consent page will be shown where LinkedIn will tell the user what are the information that the client will be able to access and what actions it would be able to perform on behalf of you after allowing the access.


Here you can provide your linkedin credentials (to the linkedin website itself) and Allow the client web application to access your linkedin profile details.

Then the browser will be redirected to the callback URL of your client application (which you set in the OAuth application on linkedin) and in the query parameter, it will receive the authoriztion code and the value for the state. Here the value for the state should be the same value we sent along with the request (to avoid CSRF attacks).

Here’s the sample response I got.


I can extract the code (authorization code) from the response which should be sent back to LinkedIn for obtaining the access token.

These are the values I got in the response.

code
AQQ661oSvY6YVN1V26y8EC8Jzaf7O2PYPJv2FOGKUaSf_pAHFJIuT4778FmdFrNaubnFDkJrzKhN7rihoL7L9MH-7qxgj1kunCuGbh3WG94KHOM_Wn4
state
123456


Step 3 — Exchange Authorization Code for an Access Token

In this step, we need to send a request to the OAuth token endpoint of LinkedIn with the authorization code we received in the previous step to obtain the OAuth access token for consuming LinkedIn APIs.

Here we need to send a POST request to https://www.linkedin.com/uas/oauth2/accessToken with Content-Type: application/x-www-form-urlencoded header. In the body of the request, we need to send the following parameters where the values should be URL encoded.

Parameter
Description
Required
grant_type
The value of this field should always be: authorization_code
Yes
code
The authorization code you received from Step 2.
Yes
redirect_uri
The same 'redirect_uri' value that you passed in the previous step.
Yes
client_id
The "API Key" value generated Step 1.
Yes
client_secret
Yes


These are the sample values that I am using where except grant_type, you will have to use your own values when trying this out.

Parameter
Sample Value
URL Encoded Value
grant_type
authorization_code
authorization_code
code
AQQ661oSvY6YVN1V26y8EC8Jzaf7O2PYPJv2FOGKUaSf_pAHFJIuT4778FmdFrNaubnFDkJrzKhN7rihoL7L9MH-7qxgj1kunCuGbh3WG94KHOM_Wn4
AQQ661oSvY6YVN1V26y8EC8Jzaf7O2PYPJv2FOGKUaSf_pAHFJIuT4778FmdFrNaubnFDkJrzKhN7rihoL7L9MH-7qxgj1kunCuGbh3WG94KHOM_Wn4
redirect_uri
http://localhost:8080/mylinkedinoauthapp/callback
http%3A%2F%2Flocalhost%3A8080%2Fmylinkedinoauthapp%2Fcallback
client_id
75kkcu5le8hca0
75kkcu5le8hca0
client_secret
KNuJ1HnOJU2ebDwM
KNuJ1HnOJU2ebDwM


Here’s the sample request that I need to make.

POST /uas/oauth2/accessToken HTTP/1.1
Host: www.linkedin.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=AQQ661oSvY6YVN1V26y8EC8Jzaf7O2PYPJv2FOGKUaSf_pAHFJIuT4778FmdFrNaubnFDkJrzKhN7rihoL7L9MH-7qxgj1kunCuGbh3WG94KHOM_Wn4&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fmylinkedinoauthapp%2Fcallback&client_id=75kkcu5le8hca0&client_secret=KNuJ1HnOJU2ebDwM


For trying out this step without writing a client web application, I can simply use some HTTP client tool. Here I use the RESTClient firefox addon [4].



In the response, I receive the OAuth access token and the expiration time of the token. The response is in JSON format where we can use a JSON parser in our client web application to extract these values.

These are the values I received.

access_token
AQXpoZBpy9aZiHYEP2Eb4popgLQm2ZhidRiaqCGYaQD5dSlALAaIKaKu4P7Up9eFH8x1U4WcXqaak4i6PAaMIg3m7z7DGzHC3GpBtRGgX9nkBdG3QOe8mR1GlNZuyKhfJjGkNEO1CuXDaIevO5-DtXU6PxMM2CzFesFbjm_saCzVaGgBGJo
expires_in
5183999

When you are trying this out, you need to know that the authorization code you got in previous step will be expired in 20 seconds [5]. So as soon as you got the authorization code, you need to send it back to LinkedIn requesting the access token.

In the client web application you write, this request has to be a back channel call where the end user will not have access to the access token that LinkedIn sends.

Step 4 — Make authenticated requests

Now we have received an access token from LinkedIn. Using this access token, we (the client application) can request the particular user’s profile details from linkedin. Here is a sample request. When you are trying this out, you need to use the access token value that you obtained from linkedin.

GET /v1/people/~ HTTP/1.1
Host: api.linkedin.com
Connection: Keep-Alive
Authorization: Bearer AQXpoZBpy9aZiHYEP2Eb4popgLQm2ZhidRiaqCGYaQD5dSlALAaIKaKu4P7Up9eFH8x1U4WcXqaak4i6PAaMIg3m7z7DGzHC3GpBtRGgX9nkBdG3QOe8mR1GlNZuyKhfJjGkNEO1CuXDaIevO5-DtXU6PxMM2CzFesFbjm_saCzVaGgBGJo

A sample request would be as following. The particular user profile fields that we need to retrieve should be included in the request as a comma separated list.



This also I try out in the RESTClient browser addon.


In the response, I receive the requested fields of the user’s profile.

{
 "emailAddress": "tharispc@xxxxx.com",
 "firstName": "Tharindu",
 "headline": "Security Engineer at WSO2 Platform Security Team",
 "id": "XkkQo-Oe96",
 "industry": "Information Technology and Services",
 "lastName": "Edirisinghe",
 "pictureUrl": "https://media.licdn.com/mpr/mprx/0_tahxOFyLNhWT7h7xcoNtrzJL9bkh7ru1t4nxR1RXzXhT7hgxOa4lPzJLPvuToAr-toNxrks5MGP32qRORgL_91cWpGP82qJ1YgLyj-GkciQ26GG7-2P-gQ2vyBWK5qmGcOTPs2BTxn3",
 "publicProfileUrl": "https://www.linkedin.com/in/ediri"
}

If you write a client web application, this request also should happen as a back channel call so that the user does not have access to the access token that the web application pocesses.

So in your client web application, you can extract these values and use them appropriately. Either you can consider the user as an authenticated user to your application or else you can use these information to fill out a signup form in your website and ask the user to create an account in your website. Either way you are making the life easier for the end users of your website. If you authenticate the user to your website trusting the external identity provider (here LinkedIn), you remove the burden of remembering credentials for the user to your website.

In my next blog post, I will share details on writing a sample client web application in Java for performing the above steps and consumer LinkedIn APIs.

References

[1] The OAuth 2.0 Authorization Framework  https://tools.ietf.org/html/rfc6749

Tharindu Edirisinghe
Platform Security Team
WSO2

1 comment:

  1. The OAuth apps allowed in linkedin profile can be viewed from [1].

    [1] https://www.linkedin.com/psettings/third-party-applications

    ReplyDelete