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:
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