in reply to Obtaining OAuth2 Access Token

Here is a bit more meat on the question with a working Twitter example:

I have a simple working system - written a long time ago so go easy on my code! - that allows any Twitter user to see who they follow and who follows them back and follow/unfollow them from that list. You can see this on my website and it demonstrates the workflow for OAuth2 albeit using Net::Twitter to do the connection work.

Here is the code that does the work with Twitter taken from the live site:

#!/usr/bin/perl use cPanelUserConfig; use Net::Twitter; use Data::Dumper; use JSON; use POSIX qw(strftime); require "incl/common.pl"; require "incl/html.pl"; $page_size = 140; $login_days = 10; my $twitter=Net::Twitter->new( traits => ['API::RESTv1_1'], consumer_key => 'xxxxxxxxxx', consumer_secret => 'xxxxxxxxxxxxxxxxxxxx', callback => "https://$ENV{'SERVER_NAME'}/cgi-bin/twitte +r.pl?command=authorize", ssl => 1, source => 'BodBot', ); if ($cookie{'Twitter_tok'} and $cookie{'Twitter_sec'}) { $twitter->access_token($cookie{'Twitter_tok'}); $twitter->access_token_secret($cookie{'Twitter_sec'}); } # Code to start the authorisation process sub twitter { $auth_url=$twitter->get_authorization_url(callback => "http://$ENV +{'SERVER_NAME'}/cgi-bin/twitter.pl?command=authorize"); print "Location: $auth_url\n\n"; exit 0; } # Callback from Twitter sub authorize { eval{($access_token, $access_token_secret, $user_id, $screen_name) +=$twitter->request_access_token(token => $data{'oauth_token'}, token_ +secret => 'xxxxxxxxxxxxxxxxxxxx', verifier => $data{'oauth_verifier'} +);}; if ($@) { print "content-type: text/plain\n\n"; print "ERROR:\n$@\n"; exit 1; } &log("Access token obtained for \@$screen_name"); $twitter->access_token($access_token); $twitter->access_token_secret($access_token_secret); $expiry="; expires=".(strftime "%a, %d-%b-%Y %H:%M:%S",(gmtime(tim +e() + $login_days*24*3600)))." GMT"; print "Set-cookie: Twitter_tok=$access_token; path=/; expires=$exp +iry\n"; print "Set-cookie: Twitter_sec=$access_token_secret; path=/; expir +es=$expiry\n"; print "Location: http://$ENV{'SERVER_NAME'}/cgi-bin/twitter.pl\n\n +"; exit 0; } # Logout and interact with Twitter sub logout { print "Set-cookie: Twitter_tok=xxx; path=/; expires=Thu, 01-Jan-19 +70 00:00:01 GMT\n"; print "Set-cookie: Twitter_sec=xxx; path=/; expires=Thu, 01-Jan-19 +70 00:00:01 GMT\n"; print "Location: http://$ENV{'SERVER_NAME'}/cgi-bin/twitter.pl\n\n +"; exit 0; } sub XHRfollow { $result=$twitter->create_friend({ user_id => $data{'user'} }); exit 0; } sub XHRunfollow { $result=$twitter->destroy_friend({ user_id => $data{'user'} }); exit 0; }
That shows an OAuth2 workflow that functions as it should.

For LinkedIn the general arrangement should work the same. Except that LinkedIn only passes back a code parameter - it doesn't pass back oauth_token or oauth_verifier. Instead the error is Token endpoint missing expected token_type in successful response. with a payload of:

{ "serviceErrorCode": 65604, "message": "Empty oauth2 access token", "status": 401 }
The LinkedIn API documentation doesn't seem very helpful to me.

Here is what I am trying...you can see this working on my test website. This runs exactly this code but with real keys. The callback URL is authorised to be used within LinkedIn.

#!/usr/bin/perl use CGI::Carp qw(fatalsToBrowser); use cPanelUserConfig; use LWP::Authen::OAuth2; use Data::Dumper; use strict; use warnings; our %data; require "incl/common.pl"; my $linkedin = LWP::Authen::OAuth2->new( client_id => 'xxxxxxxxxx', client_secret => 'xxxxxxxxxx', authorization_endpoint => 'https://api.linkedin.com/uas/oauth2/ +authorization', token_endpoint => 'https://api.linkedin.com/v2/accessT +oken', redirect_uri => "https://$ENV{'HTTP_HOST'}/cgi-bin/link +edin.pl?command=authorize_linkedin", scope => 'w_member_social', ); if ($data{'command'} eq 'linkedin') { my $auth_url = $linkedin->authorization_url; print "Location: $auth_url\n\n"; exit 0; } if ($data{'command'} eq 'authorize_linkedin') { print "Content-type: text-plain\n\n"; my $token = $linkedin->request_tokens( code => $data{'code'}, ); print "TOKEN: $token\n"; } print<<"END_HTML"; Content-type: text/html <html> <body> <input type="button" value="LinkedIn" onClick="document.location.href= +'?command=linkedin';"> </body> </html> END_HTML
The require just populates %data with the key/value pairs from the query string.