
Laravel in Practice – pulling user data from LinkedIn
Not so long ago I have posted a very detailed tutorial on how to use “Login with Facebook” with your Laravel application. After I published that tutorial I have found an extraordinary oAuth2 package that makes it a lot more consistent and easy to integrate social providers into any Composer-based PHP application. Since then I have contributed to that package by integrating more providers such as Microsoft, Instagram and finally, LinkedIn.
In this post I will explain how to use this library in Laravel and how you can make it work with LinkedIn to pull in an enormous amount of data about the user that authorizes the application to use their LinkedIn profile.
You can get the source for this tutorial on my Github: https://github.com/msurguy/laravel-linkedin-login
And the demo of this app is here: http://laravel-linkedin-login.gopagoda.com
The process of creating a simple app that integrates with Linkedin will follow this flow:
- Install the above mentioned oAuth2 package
- Create LinkedIn application on the LinkedIn developers site
- Configure the social providers (in this case LinkedIn)
- Use the auth to gather the data about the user
- Celebrate!
This is how the end result will look like (just a small snapshot of all the data I got from LinkedIn):
Are you ready to pull some useful info from LinkedIn user? Let’s start!
oAuth2 client package installation
Let’s assume you already have a Laravel project setup (it could even be a fresh project). First step for us to do is install the oAuth2 package, open up the terminal navigating to the root of the application’s directory, and ask Composer to install the “league/oauth2-client” package by typing:
composer require league/oauth2-client
And in the prompt about the version constraint provide “dev-master”, hit enter and you should have the package installed after a couple minutes. The oAuth2 client package is now installed, let’s create an alias to it in the “app/config/app.php” file so that we have easier way to use it later in the application, open up the app.php config file, scroll down to the “aliases” and add the alias to the LinkedIn class:
...
'URL' => 'IlluminateSupportFacadesURL',
'Validator' => 'IlluminateSupportFacadesValidator',
'View' => 'IlluminateSupportFacadesView',
'Linkedin' => 'LeagueOAuth2ClientProviderLinkedin',
LinkedIn app configuration
At this point we can already use the package but of course before we try to do any authorization we need to set up an application with LinkedIn. Go to this link to create a new application : https://www.linkedin.com/secure/developer.
Fill out the fields like I did in the screenshot:
Also, select the permissions that you would like to request from the users (you will need these later when we retrieve user’s data):
When you have the application created, make note of the Api key and the Secret key. Copy them somewhere as you will need them in the next step. It is time to configure our settings for LinkedIn inside the Laravel application.
Configuring social provider settings
Just like I have mentioned in the previous tutorial, it is a good idea to create a configuration file for the social providers instead of cluttering the controllers or routes with these settings. We will do the same here, let’s create a file called “social.php” and place it in the “app/config” folder, it will contain the Api key and secret key settings (that you copied from your app settings in Linkedin), the URL where to redirect after authorization and the desired scope for linkedin permissions:
<?php
// Social apps keys
return array(
'linkedin' => array(
'clientId' => 'your_app_client_id',
'clientSecret' => 'your_app_client_secret',
'redirectUri' => url('login/linkedin'),
'scope' => 'r_basicprofile r_emailaddress r_contactinfo r_fullprofile',
),
);
The important part here is that the ‘scopes’ should match the scopes you have requested when you were creating the LinkedIn app (see screenshot above). So now with the keys in place we can make use of LinkedIn Auth and pull user’s data easily. I will create two routes that will do the following, route “login/linkedin” first:
- Authorize Linkedin user (ask the user for permission to share data) and go back to login/linkedin with a oAuth provider code
- Get an access token Using the code provided by the oAuth provider
- With the access token received in previous step request user’s data from Linkedin, the list of user data requested is specified in the $resource variable according to LinkedIn API docs
- Receive the data from LinkedIn and pass it to the second route that will display the information
Route::get('login/linkedin', function()
{
$provider = new Linkedin(Config::get('social.linkedin'));
if ( !Input::has('code')) {
// If we don't have an authorization code, get one
$provider->authorize();
} else {
try {
// Try to get an access token (using the authorization code grant)
$t = $provider->getAccessToken('authorization_code', array('code' => Input::get('code')));
try {
// We got an access token, let's now get the user's details
$userDetails = $provider->getUserDetails($t);
$resource = '/v1/people/~:(firstName,lastName,pictureUrl,positions,educations,threeCurrentPositions,threePastPositions,dateOfBirth,location)';
$params = array('oauth2_access_token' => $t->accessToken, 'format' => 'json');
$url = 'https://api.linkedin.com' . $resource . '?' . http_build_query($params);
$context = stream_context_create(array('http' => array('method' => 'GET')));
$response = file_get_contents($url, false, $context);
$data = json_decode($response);
return Redirect::to('/')->with('data',$data);
} catch (Exception $e) {
return 'Unable to get user details';
}
} catch (Exception $e) {
return 'Unable to get access token';
}
}
});
In my case I am just redirecting to the index page of the application to show the user’s data, but you could do all kinds of things like creating a new user or looking if a user with this LinkedIn uid already exists in the DB and log them in, in other words feel free to come up with a way to use the data!
Here is the index route for clarity (I use it only to pass the data to the view):
Route::get('/', function()
{
$data = Session::get('data');
return View::make('user')->with('data', $data);
});
And the view template that displays the received data (user.blade.php):
@extends('layouts/layout')
@section('content')
@if (isset($data))
<div class="media">
<a class="pull-left" href="#">
<img class="media-object" src="{{ $data->pictureUrl }}" alt="Profile image">
</a>
<div class="media-body">
<h4 class="media-heading">Name: </h4>
<p>{{$data->firstName .' '.$data->lastName}}</p>
<h4 class="media-heading">Date of Birth: </h4>
<p>{{$data->dateOfBirth->day .'/'.$data->dateOfBirth->month.'/'.$data->dateOfBirth->year}}</p>
<h4 class="media-heading">Location: </h4>
<p>{{$data->location->country->code .' ,'.$data->location->name }}</p>
<h4 class="media-heading">All captured info: </h4>
<pre>{{var_dump($data)}}</pre>
</div>
</div>
@else
<div class="jumbotron">
<h1>LinkedIn login and data pull</h1>
<p>Created by <a href="http://twitter.com/msurguy" target="_blank">Maks</a></p>
<p class="text-center">
<a class="btn btn-lg btn-info" href="{{url('login/linkedin')}}"><i class="icon-linkedin"></i> | Login with LinkedIn</a>
</p>
</div>
@endif
@stop
And what this does is it gives us LinkedIn data in a nice object format that we can display back to the user. This is neat and useful to me, I hope you also found this useful and if you did, please consider following me on Twitter to keep up to date!