Oauth is an open standard for authorization that allows secure authorization from web, mobile and desktop applications. This standard allows a third-party application to gain access to a HTTP service, i.e. it enables users to share their resources from one website with another website without having to give out their credentials (usually username and password). Oauth is implemented on websites that support web and mobile applications or have their own APIs. Many popular websites, such as Google, Facebook and Twitter, use Oauth for third-party application authorization.
How Does Oauth Authorization Work?
Oauth authorization is carried out in 3 steps:
- Obtain a request token
- Authorize request token
- Exchange request token for an access token
Obtaining a request token is done by sending a request to an API end-point with parameters defined by the particular website you want to gain access to. The user is now redirected to the service provider website in order to authorize the request token. The token is authorized if the user logs in and allows your application to access his data. After confirmation, the user is redirected back to your website along with a request token. Now, your website needs to make another request to the service provider to exchange the request token for an access token. If everything is correct, the access token is sent back. Oauth standard does not specify token expiration, so some of the websites make them expire after 1-2 hours and some of them use non-expiring access tokens. Keep in mind that the user can revoke a granted token at any time, making the token invalid and blocking the application from accessing his data.
In order to get a better image of Oauth authentication, take a look at the workflow diagram:
Oauth authentication workflow diagram
The implementation of Oauth is slightly different for each website. I’ll explain and provide PHP code, which can be used to authenticate your application on Facebook, Twitter and Foursquare. I will be using some helper functions which you can see here.
Facebook Authentication
There are two ways of authenticating on Facebook: Using JavaScript SDK or using PHP SDK. The first method is much simpler, since you just have to load the Facebook’s JavaScript and run some functions. First, add this code to the bottom of the page:
<script src="http://connect.facebook.net/en_US/all.js"></script> <script> FB.init({ appId : '<?php echo YOUR_APP_ID;?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true, // parse XFBML oauth : true // enables OAuth 2.0 }); </script>
Now, when you want to authorize your application, use this:
FB.login(function(response) { if (response.authResponse) { var access_token = FB.getAuthResponse()['accessToken']; // get access token into a variable console.log('Welcome! Fetching your information…. '); FB.api('/me', function(response) { console.log('Good to see you, ' + response.name + '.'); $('#fb_access_token').val(access_token); // do something with access token here }); } else { console.log('User cancelled login or did not fully authorize.'); // generate an error here } },{scope: 'email,user_birthday,user });
The scope parameter is important here. Scope is the data you want to access. Usually, the more data you request, the less is the chance that the user would approve your application.
The second way of authenticating on Facebook is to use Facebook PHP SDK. This approach is used when you have to do server-side authentication. PHP SDK can be downloaded from Facebook’s website and it is a PHP class that can make the whole process easier. Use one PHP page only:
<?php $facebook = new Facebook(array( 'appId' => YOUR_APP_ID, 'secret' => YOUR_APP_SECRET, )); $user = $facebook->getUser(); if ($user) { $token = $facebook->getAccessToken(); //get access token //store the token } else { $args['scope'] = 'email'; // scope parameter, separate multiple scopes by comma $loginUrl = $facebook->getLoginUrl($args); //generate login url } ?>
The code above handles the whole authentication process. If the user is already logged in, the access token is just fetched; if not, the login URL is generated. Scope is passed as an argument to the function, and the redirect uri parameter is automatically set to current URL, which means that this page redirects back to itself after Facebook authentication.
Twitter Authentication
Before creating Twitter authorization in PHP, you need to edit your Twitter application settings. The important line is callback URL, which must not be left blank. After that, let’s introduce Twitter API endpoints, which will be used during authorization and for fetching the data later:
class Twitter { const AUTHORIZE_URI = 'https://api.twitter.com/oauth/authorize'; const REQUEST_URI = 'https://api.twitter.com/oauth/request_token'; const ACCESS_URI = 'https://api.twitter.com/oauth/access_token'; const API_URI = 'https://api.twitter.com/'; private $consumer_key = FALSE; private $consumer_secret = FALSE; private $method; private $algorithm; }
All functions mentioned below are part of this very same class. Consumer key and consumer secret are obtained upon creating the application; method is GET and algorithm HMAC-SHA1. Twitter does not send parameters using the POST method, but passes them in the HTTP header. Now, we start with step no. 1 and want to get a request token:
public function get_request_token($callback) { //Generate an array with the initial oauth values we need $auth = build_auth_array(self::REQUEST_URI, $this->consumer_key, $this->consumer_secret, array('oauth_callback' => urlencode($callback)), $this->method, $this->algorithm); $str = build_auth_string($auth); // build auth string which will be added to HTTP header //Send the request $response = connect(self::REQUEST_URI, $str); //We should get back a request token and secret which //we will add to the redirect url. parse_str($response, $resarray); // parse the response string into array return $resarray; }
$callback
is the URL to which the request token will be passed. Usually, it is the page that will eventually make a request to get the access token. For example, the page www.yourdomain.com/request_token.php would look like this:
<?php $twitter = new Twitter(); // the class from above , where all the functions are stored $response = $twitter->get_request_token('http://www.yourdomain.com/access_token.php'); $_SESSION['twitter_token'] = $response['oauth_token']; $_SESSION['twitter_token_secret'] = $response['oauth_token_secret']; header("Location:". self::AUTHORIZE_URI."?oauth_token={$token}"); ?>
If the user has authorized your application, he would be redirected to access_token.php:
<?php $twitter = new Twitter(); $response = $twitter->get_access_token(FALSE, $_SESSION['twitter_token_secret']); if(is_array($response) && !empty($response['oauth_token'])) { // success, store the access token $_SESSION['twitter_oauth_token'] = $response['oauth_token']; $_SESSION['twitter_oauth_token_secret'] = $response['oauth_token_secret']; $_SESSION['twitter_screen_name'] = $response['screen_name']; } else { //generate error here } ?>
Function get_access_token:
public function get_access_token($token = FALSE, $secret = FALSE, $verifier = FALSE) { //If no request token was specified then attempt to get one from the url if($token === FALSE && isset($_GET['oauth_token'])) { $token = $_GET['oauth_token']; } if($verifier === FALSE && isset($_GET['oauth_verifier'])) { $verifier = $_GET['oauth_verifier']; } //If all else fails attempt to get it from the request uri. if($token === FALSE && $verifier === FALSE) { $uri = $_SERVER['REQUEST_URI']; $uriparts = explode('?', $uri); $authfields = array(); parse_str($uriparts[1], $authfields); $token = $authfields['oauth_token']; $verifier = $authfields['oauth_verifier']; } $tokenddata = array('oauth_token' => urlencode($token), 'oauth_verifier' => urlencode($verifier)); if($secret !== FALSE) { $tokenddata['oauth_token_secret'] = urlencode($secret); } //Include the token and verifier into the header request. $auth = get_auth_header(self::ACCESS_URI, $this->consumer_key, $this->consumer_secret, $tokenddata, $this->method, $this->algorithm); $response = connect(self::ACCESS_URI, $auth); //Parse the response into an array it should contain //both the access token and the secret key. (You only //need the secret key if you use HMAC-SHA1 signatures.) parse_str($response, $oauth); //Return the token and secret for storage return $oauth; }
Upon executing the PHP file access_token.php, you need to save the token into the database for future use. Twitter does not expire Oauth tokens.
Foursquare Authentication
Foursquare authentication is similar to authenticating on Twitter, since Foursquare does not expire access tokens. Client id and client secret are provided upon registering your application on Foursquare. Foursquare API endpoints are as follows:
class Foursquare { const API_URI = 'https://api.foursquare.com/v2/'; const AUTHORIZE_URI = 'https://foursquare.com/oauth2/authenticate'; const ACCESS_URI = 'https://foursquare.com/oauth2/access_token'; const VERSION = '20120228'; private $client_id = FALSE; private $client_secret = FALSE; private $method; private $algorithm; }
Request token request has 3 parameters: client_id, response_type (value is always “code”) and redirect_uri. They are sent as a GET request.
public function get_request_token($callback) { $params = array('client_id' => $this->client_id, 'response_type' => "code", 'redirect_uri' => $callback); $url = self::AUTHORIZE_URI.'?'.http_build_query($params,'','&'); return $url; }
After generating the request token URL, the user is redirected to that URL, which is done in request_token.php:
<?php $foursquare = new Foursquare(); // the class from above , where all the functions are stored $url = $foursquare->get_request_token('http://www.yourdomain.com/access_token.php'); header("Location:". $url); ?>
After authorizing the application, the code parameter is passed back to redirect_uri provided earlier. This code is used to get an access token:
public function get_access_token($code,$redirect) { $params = array('client_id' => $this->client_id, 'client_secret' => $this->client_secret, 'grant_type' => "authorization_code", 'redirect_uri' => $redirect, 'code' => $code); $url = self::ACCESS_URI.'?'.http_build_query($params,'','&'); //Include the token and verifier into the header request. $auth = get_auth_header(self::ACCESS_URI, $this->client_id, $this->client_secret, $params, $this->method, $this->algorithm); $response = connect($url); //Parse the json response $json = json_decode($response); if (property_exists($json,'access_token')) { return $json->access_token; } return 0; }
So, access_token.php contains the following code:
<?php $foursquare = new Foursquare(); $access_token = $foursquare->get_access_token($_GET['code'],'access_token.php'); if(!empty($access_token)) { $_SESSION['foursquare_oauth_token'] = $access_token; } else { //generate error here } ?>