I'm experimenting with some basic AuthSub authorization to test out the Google Data API (I'm interested in using the Picasa API). I'm having trouble getting my head around the steps involved in going from requesting the authorization token, to getting the URL with the token, to actually making requests to the server using the token.
Can someone please give me an idea of how I would take the token and then make a request to the server using PHP? Will there have to be Javascript involved?
Also, on a super basic level, when the Google example spells out the following, what language is it, and where would it actually appear like this in code?
GET https://www.google.com/accounts/accounts/AuthSubSessionToken
Authorization: AuthSub token="yourAuthToken"
Thanks for the help, and I'm happy to clarify since I understand these are broad questions.
GET https://www.google.com/accounts/accounts/AuthSubSessionToken
Authorization: AuthSub token="yourAuthToken"
This is the HTTP request that you should be making, and the example above means that you should include the Authorization field in the headers of an HTTP GET request that you will be making, independent of the language.
You can use PHP's cURL to make this request,
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/accounts/accounts/AuthSubSessionToken");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); # return output as string instead of printing it out
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: AuthSub token="yourAuthToken"');
$response = curl_exec($ch);
Where is the code that you are using so far?
Related
I've been trying to implement a "Login with Yahoo" option in my PHP site. I was able to do the first step which is to get the access token, as described here: https://developer.yahoo.com/oauth2/guide/flows_authcode/
But I'm struggling to get the user data. To me their directions are not completely clear: https://developer.yahoo.com/oauth2/guide/get-user-inf/Get-User-Info-API.html
I've tried doing a call to https://api.login.yahoo.com/openid/v1/userinfo and passing the access token in a header like so: Authorization: Bearer <access_token> , I also tried passing the access token as a parameter in the url, and also as a post parameter.
Whatever i do i just get an empty string as a response. Has anyone dealt with Yahoo's user api endpoint?
This is my code (after getting access token):
$access_token = $res->access_token;
$token_type = $res->token_type;
$expires_in = $res->expires_in;
$refresh_token = $res->refresh_token;
$id_token = $res->id_token;
$host = urlencode("api.login.yahoo.com");
$userbody = "access_token=$access_token&Host=$host";
$userch = curl_init();
curl_setopt($userch, CURLOPT_URL, "https://api.login.yahoo.com/openid/v1/userinfo/");
curl_setopt($userch, CURLINFO_HEADER_OUT, true);
curl_setopt($userch, CURLINFO_HEADER, true);
curl_setopt($userch, CURLOPT_HTTPHEADER, array("GET /openid/v1/userinfo HTTP/1.1",
"Host: api.login.yahoo.com",
"Authorization: Bearer $access_token"));
curl_setopt($userch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($userch,CURLOPT_AUTOREFERER, true);
$user = curl_exec($userch);
curl_close($userch);
var_dump($user);
** EDIT **
After using postman I got the right request, you're suppossed to pass id_token as a parameter in the url (they DON'T specify this in their guide), like so:
https://api.login.yahoo.com/openid/v1/userinfo?id_token=<id_token>
And the only header needed (at least in postman) is:
Authorization: Bearer <access_token>
However, even though i get the user data in postman, i still get only an empty string in my php script. Any idea why this might be happening?
After using postman I got the right request, you're suppossed to pass id_token as a parameter in the url (they DON'T specify this in their guide), like so:
https://api.login.yahoo.com/openid/v1/userinfo?id_token=<id_token>
And the only header needed (at least in postman) is:
Authorization: Bearer <access_token>
I've noticed that this situation occurs with old Yahoo apps. I had one created 4+ years ago.
Just create a new Yahoo app , and update the credentials.
I've been going round in circles trying to get this bit of code working. The problem I am facing is that there could be any number of places where something is wrong and I'm not experienced enough with cURL and API requests to know if I've just done something simple and silly somewhere. The code below is supposed to fetch a JSON response. What I am currently getting is "false". The API developer keeps giving me a CLI sample and I don't know how to "translate" that into something I can use in PHP.
I have to hide the domain, service name and authentication details in my examples.
The string I was given:
'https://[domain]/agw/latest/services/[service]-api/latest/api/v2/[service]-actual-prizes -vk -H "Proxy-Authorization: Basic [authstr]"'
([authstr] is the username and password, separated by a colon and BASE64 encoded - the API dev has confirmed that my authorisation string is correct)
What I have been trying:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://[domain]/agw/latest/services/lottery-api/latest/api/v2/sportka-actual-prizes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Proxy-Authorization: Basic '.$authstr.'"
,"Content-type: application/json"
));
$response = curl_exec($ch);
curl_close($ch);
var_dump($response);
If I understand this correctly (and I'm not sure that I do), then I'm passing the URL (without flags), saying that I don't want a header in the response (I've tried TRUE as well without any success) and then passing headers with my request that includes the authorisation.
I've tried file_get_contents with a stream_context_create header but that fails too.
Am I missing a header option or flag or something in my cURL code?
Previously I have been able to access the Facebook OAuth services through cURL in PHP. However, I am now getting a 2500 error (In this case An active access token must be used to query information about the current user.). I can access the information by using the URL straight through my web browser, however when I try to access it with cURL in PHP it doesnt work. I am using Facebook API v1.0, and the token is being generated with the Graph API Explorer.
What I have tried
I have tried creating a new access token, as well as tried using Facebook API v2.0 and the unversioned API. As I said above, I have tried using the exact same URLs in my browser, which works. I have also tried clearing cookies and trying again, as well as trying a whole different browser.
I have seen some of the other questions on SO which relate to this question but none of the answers work for me.
The code
The URL I am using is simply a call to the /me/home edge.
https://graph.facebook.com/v1.0/me/home/?since=1402913078&until=1402913213&access_token=<access token here>
Where <access token here> is the access token
The PHP cURL code looks like the following:
$url = "<the url here>";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
// get the response here...
It turns out that the actual URL being requested by cURL was different to the one that should have been being requested (the GET parameters were missing). This was caused by another location in the code.
To verify that the URL that is being requested is the same as the one passed to cURL, use the following code:
$requested_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
I have a simple PHP API. I just used cURL for the Client and $_POST to accept the requests at the Server side. Something like ..
Client:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/api-server");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('q' => 'world!'));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
$response = curl_exec($ch);
curl_close($ch);
echo json_decode($response);
?>
Server:
<?php
echo json_encode("hello, ".$_POST["q"]);
?>
My questions here are:
Am i even still following the standard API logic anyway?
How to "PROTECT" this API Server Access?
Okay i found it here for what i asked above:
http://php.net/manual/en/features.http-auth.php
It simply used, for API page:
if ( $_SERVER['PHP_AUTH_USER'] == $MY_API_USER && $_SERVER['PHP_AUTH_PW'] == $MY_API_PW) {
..
..
} else {
header('WWW-Authenticate: Basic realm="Sorry, this API is protected. You may need a valid authentication."');
header('HTTP/1.0 401 Unauthorized');
exit;
}
At the Caller/requester end, add this two lines into the cURL calls:
..
curl_setopt($ch, CURLOPT_USERPWD, $MY_API_USER.":".$MY_API_PWD);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
..
Thats simply all, for me.
Dont try & write an API engine, these are industry standard. Look at Soap or REST.
Here are some of the libraries out there that will do all the heavy lifting:
Soap server http://framework.zend.com/manual/2.0/en/modules/zend.soap.server.html
Soap client http://framework.zend.com/manual/2.0/en/modules/zend.soap.client.html
Rest server
Rest client
Then to protect these you could use basic http protection, through to OAuth etc
While there are well defined communication protocols such as HTTP, and transport formats such as JSON, the actual implementation of a API architecture is left to the developer.
Many existing tools, from complete frameworks to modular components, exist to assist in the construction of an API layer, but at the end of the day you need to build something that works.
If you need a server, focus on the server, and focus on an implementation that adheres to standards when available, and best practices otherwise; including facets such as resource architecture, authentication, and so forth.
Right now, you're spewing out some query parameter concatenated JSON. I doubt that's the intended final result, unless you're after an echo server.
Model your API after a service, or domain model; expose methods and properties as resources of your API layer.
Addendum: Oh, and as for "protection"; the already mentioned techniques of HTTP Basic or OAuth are good candidates, but as is the core of my answer: it depends on what you need.
I have written a very simple application to update my twitter status on a given condition. I have used the twitter documentation to understand the requirements of creating the OAuth signature and also how to structure the Authorization header. I then send the request with cURL in PHP.
Using the OAuth Tools on the twitter dev site, I compared both my signature base string and authorization header, and both are exactly the same:
Signature Base String
POST&https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&oauth_consumer_key%3DYNxxxxxxxxxxxWnfI6HA%26oauth_nonce%3D31077a3c7b7bee4e4c7e2b5185041c12%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1340729904%26oauth_token%3D2991771-4csoiO2fxmWgSxxxxxxxxxxDjWj2AbyxATtiuadNE%26oauth_version%3D1.0%26status%3Dblah%2520test%2520blah.
Authorization header
Authorization: OAuth oauth_consumer_key="YN4FLBxxxxxxxxxxI6HA", oauth_nonce="31077a3c7b7bee4e4c7e2b5185041c12", oauth_signature="M2cXepcxxxxxxxxxxAImeAjE%2FHc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1340729904", oauth_token="2991771-4cxxxxxxxxxxSmRvjzMoooMDjWj2AbyxATtiuadNE", oauth_version="1.0"
Obviously I've replaced some characters with x to hide my data, but comparing the two character for character yields exactly the same result. For reference, I hard-code the timestamp and nonce that the OAuth Tool generates so that my values can be the same for checking. My access level is set to Read and write. On that same page there is a final example - the command to run with cURL on the command line. When I run this command, it works perfectly and posts to my twitter feed with no issue.
With that in mind I believe everything I've created so far is fine, and don't think there's much point me posting the code that generates the details mentioned previously. However the code that I use to make the call, using cURL, I think is the culprit, but can't tell why:
<?php
// ...
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $baseUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: $header"));
curl_setopt($curl, CURLOPT_POSTFIELDS, array('status' => $status));
$result = json_decode(curl_exec($curl));
curl_close($curl);
var_dump($result);
Note that $baseUrl, $header and $status are the same variables used in generating the signature base string and authorization header, which matched just fine.
The output of the page when run is:
object(stdClass)#1 (2) { ["error"]=> string(34) "Could not authenticate with OAuth." ["request"]=> string(23) "/1/statuses/update.json" }
I hope there are enough details here for someone to point me in the right direction!
After much more searching, testing with apache_request_headers() and sticking to the notion that my data was fine and it was cURL where the problem laid, I realised that cURL was setting the Content-type of the request as multipart/form-data; and adding boundary information, obviously with a longer Content-Length field too. This meant that the status wasn't getting sent correct, I presume because of a malformed multipart/form-data; request.
The solution was to send it as a string. For instance, this works:
curl_setopt($curl, CURLOPT_POSTFIELDS, 'status='. rawurlencode($status));
But I found that there's an even nicer way (especially with multiple values, when I want to use an array):
$postfields = array('status' => $status);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postfields));
which looks much nicer IMHO.
I think it's your nonce. From the docs: "The oauth_nonce parameter is a unique token your application should generate for each unique request" (emphasis mine).
Caveat: I'm more familiar with OAuth 2 + Java or JavaScript rather than OAuth 1 + PHP.
If that's not it (or not the only thing), you could compare your actual HTTP request (e.g. using WireShark) to the sample request they document on that page. The note there on "Building the header string" may help too.