Tuesday, November 11, 2014

In this post, I want to take a short detour to discuss OAuth API calls. This is a widely used pattern of API authorization. The API server merely issues a redirect to a web page where the user can login. The API server knows nothing about the user until it receives a callback from the referral site. When the callback comes, there is a module either in the API server or in the referral site called the OAuth Token provider that looks up the associated user and client to issue a token. When the token is issued, it is sent to the user who can use the api_key and token in making the API calls. Each API call validates the token and the api_key prior to sending a response. 
Note that the API server is also allowed to be a referral to the OAuth token provider for mere convenience. This is called implicit workflow where the API server passes in the password directly to the token provider. As a sample code for this less secure method  of getting tokens, here is the OAuth call:
var xdr = new XDomainRequest();
 xdr.timeout = 10000;
xdr.onreadystatechange=function()
   {
    if (xdr.readyState==4 && xdr.status==200)
      {
   var resp = parseJSON(xdr.responseText);
   document.getElementById(params[access_token]).innerHTML=resp.access_token;
      }
        }
  xdr.open("POST","https://apiserver.com/v1/token/",true);
  xdr.setRequestHeader("Content-type","application/json");
  xdr.send("api_Key="+ document.getElementById("apiKey").value +"&grant_type=password&client_id=" + document.getElementById("apiKey").value + "&username=" + username + "&password=" + document.getElementById("password").value + "&scope=scope&client_secret=" + document.getElementById("apiSecret").value);
}

Another OAuth API token grant sequence is the authorization code grant. Here a code is issued and then the code is translated to token. From MSDN:
public static function getAuthenticationHeaderFor3LeggedFlow($code){
       // Construct the body for the STS request
        $authenticationRequestBody = "grant_type=authorization_code" . "&".                                                                         
                                     "client_id=".urlencode(Settings::$clientId) . "&".
                                     "redirect_uri=".Settings::$redirectURI . "&".
                                     "client_secret=".urlencode(Settings::$password). "&".
                                     "code=".$code;


        //Using curl to post the information and get back the authentication response   
        $ch = curl_init();
        // set url
        $stsUrl = 'https://apiserver.com/oauth2/token';
        //curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8888');
        curl_setopt($ch, CURLOPT_URL, $stsUrl);
        // Get the response back as a string
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // Mark as Post request
        curl_setopt($ch, CURLOPT_POST, 1);
        // Set the parameters for the request
        curl_setopt($ch, CURLOPT_POSTFIELDS,  $authenticationRequestBody);
        //curl_setopt($ch, CURLOPT_PROXY, '127.0.0.1:8888');

        // By default, HTTPS does not work with curl.
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        // read the output from the post request
        $output = curl_exec($ch);    
        // close curl resource to free up system resources
        curl_close($ch);
            
        //Decode the json response
        $tokenOutput = json_decode($output);
        $tokenType = $tokenOutput->{'token_type'};
        $accessToken = $tokenOutput->{'access_token'};
        $tokenScope = $tokenOutput->{'scope'};
       
        print("\t Token Type: ".$tokenType."\n AccessToken: ".$accessToken);
        // Add the token information to the session header so that we can use it to access Graph
        $_SESSION['token_type']=$tokenType;
        $_SESSION['access_token']=$accessToken;
        $_SESSION['tokenOutput'] = $tokenOutput;  

       // it is possible to decode (base64) the accessToken and search claims, such as the user's upn
       // value.
       // However, this is not recommended because in the future, the access token maybe
       // encrypted.

       // $tokenOutput = base64_decode($accessToken);
       // $subString = strstr($tokenOutput,'"upn":');
       // $subString = strstr($subString, ',',TRUE);
       // $upn = rtrim(ltrim($subString,'"upn":"'), '"');
       // $_SESSION['upn']=$upn;
  
Similarly another OAuth API token grant sequence is merely for clients and this grant_type is called client_credentials.
As an example:
<?php
function cURLcheckBasicFunctions()
{
if( !function_exists("curl_init") &&
!function_exists("curl_setopt") &&
!function_exists("curl_exec") &&
!function_exists("curl_close") ) return false;
else return true;
}

// declare
if( !cURLcheckBasicFunctions() ) print_r('UNAVAILABLE: cURL Basic Functions');
$apikey = 'your_api_key_here';
$clientId = 'your_client_id_here';
$clientSecret = 'your_client_secret_here';
$url = 'https://apiserver.com/v1/oauth/token?api_key='.$apikey;
$ch = curl_init($url);
$fields = array(
'grant_type' => urlencode('client_credentials'),
'client_id' => urlencode($clientId),
'client_secret' => urlencode($clientSecret),
'scope' => urlencode('test_scope'),
'state' => urlencode('some_state'));

//url-ify the data for the POST
$fields_string = '';
foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
rtrim($fields_string, '&');
curl_setopt($ch, CURLOPT_URL, $url);
// curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ;
// curl_setopt($ch, CURLOPT_USERPWD, $credentials);
// curl_setopt($ch, CURLOPT_SSLVERSION, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);

//execute post
if(curl_exec($ch) === false)
{
echo 'Curl error: ' . curl_error($ch);
}
else
{
echo 'Operation completed without any errors';
}

//close connection
curl_close($ch);
?>


Now that we have completed our post on this topic, I will continue my discussion from previous posts shortly.but first another coding exercise:
#codingexercise
Int GetMode (int [] A)
{
If (A == null) return 0;
Return A.Mode ();
}

No comments:

Post a Comment