blog |
Aanmelden met Oauth | 0reacties |
Iedereen die wel eens met de Twitter, Facebook of Linkedin api’s (of application programming interfaces) heeft gewerkt, weet dat ze allemaal behoorlijk beperkt zijn en dan je oauth moet begrijpen. Oauth is een autorisatie methode die meerdere stappen doorloopt om zeker te weten dat een sessie niet gehacked kan worden. En het kan een ontzettende pain-in-the-ass zijn om voor het eerst uit te vogelen.
Gelukkig maakt CakePhp het ons weer eens makkelijk door support te bieden via een vendor of een component. Geschreven door Cakebaker die ook een hele toffe Open ID component heeft gemaakt. Overigens kan de vendor-versie ook gewoon gebruikt worden als een gewone php-class. Met de Oauth component of vendor wordt het aanmelden bij Twitter, Facebook of LinkedIn heel erg eenvoudig. Helaas werkt iedere dienst wel weer op zijn eigen excentrieke manier met Oauth samen en is het alsnog zaak om voor alle API’s de documentatie er bij te houden. Om mensen op het goede spoor te zetten hier de aanmeld procedures van de API’s van Twitter, Linkedin en Facebook en van iedere dienst een call-voorbeeld:
// startTwitter() vraagt de requestToken aan, en geef als return URL finishTwitter() mee;
function startTwitter(){
$twConsumer = $this->createConsumer('JOUW-API-KEY', 'JOUW-API-SECRET');
$twitterRequestToken = $twConsumer->getRequestToken('https://api.twitter.com/oauth/request_token','jouw-url/finishTwitter');
$this->Session->write('twitter_request_token', $twitterRequestToken);
Header('Location: https://twitter.com/oauth/authenticate?oauth_token='. $twitterRequestToken->key);
}
//finishTwitter zorgt voor de eigenlijke verbinding:
function finishTwitter(){
$twitterRequestToken = $this->Session->read('twitter_request_token');
$twConsumer = $this->createConsumer('JOUW-API-KEY', 'JOUW-API-SECRET');
$twitterAccessToken = $twConsumer->getAccessToken('https://api.twitter.com/oauth/access_token', $twitterRequestToken);
$this->Session->write('twitter_access_token', $twitterAccessToken);
}
//Een call maken naar de API (in dit geval het ophalen van al mijn berichten die zijn geretweet):
function twitterApiCall(){
$at = $this->Session->read('twitter_access_token');
$consumer = $this->createConsumer('JOUW-API-KEY', 'JOUW-API-SECRET');
$stream = $consumer->get($at->key, $at->secret, 'http://api.twitter.com/1/statuses/retweets_of_me.json?page=1');
$retweets = json_decode($stream);
} |
//Voor facebook hoef je niet eerst een requestToken aan te vragen, vandaar bij 'startFacebook' een simpele verwijzing: function startFacebook(){ //lees vooral over de scope bij het aanmelden van facebook: //http://developers.facebook.com/search?path=&selection=scope Header('Location: https://www.facebook.com/dialog/oauth?client_id=JOUW-API-ID&redirect_uri=jouw-url/finishFacebook/&scope=friends_status,user_status,friends_likes,read_insights'); } //Verdere afhandeling gebeurt wederom in de 'finish' functie: function finishFacebook(){ $code = $_GET['code']; $key = 'JOUW-KEY'; $secret = 'JOUW-SECRET'; $uri = jouw-url/finishFacebook $fbConsumer = $this->createConsumer($key, $secret); $response = $fbConsumer->facebookAuth('https://graph.facebook.com/oauth/access_token?client_id='.$key.'&redirect_uri='.$uri.'&client_secret='.$secret.'&code='.$code); $params = null; parse_str($response, $params); $this->Session->write('facebook_access_token', $params['access_token']); } //Een call maken naar de API (berichten van mijn wall): function facebookApiCall(){ $af = $this->Session->read('facebook_access_token'); $graph_url = "https://graph.facebook.com/me/feed?access_token=".$af.'&limit=20'; //consumers werken niet goed met facebook, maar een eenvoudige file_get_contents weer wel. $stats = file_get_contents($graph_url); $statuses = json_decode($stats); } |
Zoals je wellicht kunt zien, heb ik voor Facebook al weer wat aanpassingen aan de component moeten doen, iedere API is verschillend, ook al gebruiken ze universele principes als Oauth, de manier van aanroepen moest in dit geval gewoon anders. Voeg daarom aan je component of vendor deze functie toe:
public function facebookAuth($tokenURL){
return $this->doPost($tokenURL, array());
} |
//wederom beginnen met de start functie:
function startLinkedin(){
$inConsumer = $this->createConsumer('JOUW-KEY','JOUW-SECRET');
$inRequestToken = $inConsumer->getRequestToken('https://api.linkedin.com/uas/oauth/requestToken','jouw-url/finishLinkedin');
$this->Session->write('in_request_token', $inRequestToken);
Header('Location: https://www.linkedin.com/uas/oauth/authenticate?oauth_token='. $inRequestToken->key);
}
//en wederom de functie om de accesToken op te slaan in een sessie:
function finishLinkedin(){
$inRequestToken = $this->Session->read('in_request_token');
$inConsumer = $this->createConsumer('JOUW-KEY', 'JOUW-SECRET');
$inAccessToken = $inConsumer->getAccessToken('https://api.linkedin.com/uas/oauth/accessToken', $inRequestToken);
//als de linkedin api servers tegenwerken (wat regelmatig het geval is) krijg je geen object terug, maar een oncomplete string... daarom altijd testen;
if(is_object($inAccessToken)){
$this->Session->write('in_access_token', $inAccessToken);
}else{
$this->Session->write('in_acces_token', '');
}
}
// een API-call maken (alle nieuwe connecties in jouw netwerk ophalen):
function linkedinApiCall(){
$ai = $this->Session->read('in_access_token');
$consumer = $this->createConsumer('JOUW-KEY', 'JOUW-SECRET');
$connections = $consumer->get($ai->key, $ai->secret, 'http://api.linkedin.com/v1/people/~/network/updates?type=CONN');
//de LinkedIN api geeft standaard weer alles terug via XML,
//en als 'tegenpool' van de decode_json() functie heb ik snel een
//process_xml functie geschreven voor Cake:
$connections = $this->process_xml($connections);
}
//de nodige process_xml functie:
function process_xml($response) {
$xml = new XML($response);
$result = $xml->toArray();
$xml->__destruct();
$xml = null;
unset($xml);
return $result;
} |
Al deze functies maken gebruik van de ‘createConsumer’ methode, die gaat als volgt:
private function createConsumer($key, $secret) {
return new OAuth_Consumer($key, $secret);
} |
Zoals je ziet maakt het dus niet zoveel uit dat alle systemen Oauth als autorisatie gebruiken; de manieren van benaderen is per API radicaal anders, omdat ieder platform weer op zijn eigen manier is gebouwd. Facebook werkt lekker met get_file_contents, terwijl dit bij Twitter en LinkedIn onmogelijk is.
Ik hoop dat deze ‘snippits’ het werken met de sociale API’s een beetje prettiger maakt, met deze tools spelen kan heel erg leuk zijn, maar als je teveel zelf moet uitzoeken kan dat een hoop frustratie opleveren. Succes!

