I am able to get temporary credentials and able to get oauth token, but when I do use the returned token to fetch user details, I'm unable to fetch it thus the error.
I am using thephpleague/oauth1-client package and created a simple controller where I followed their Twitter Sample. From this, I am getting this error
League\OAuth1\Client\Credentials\CredentialsException: Received HTTP status code [401] with message "{"errors":[{"code":32,"message":"Could not authenticate you."}]}" when getting temporary credentials. in /var/www/html/PF.Site/Apps/TipsMarketplace/vendor/league/oauth1-client/src/Client/Server/Server.php:418
and here is the sample code I've created.
$server = new Twitter(array(
'identifier' => 'my-identifier',
'secret' => 'my-secret',
'callback_uri' => "http://localhost:8080/twitter/auth",
));
session_start();
if (isset($_GET['user'])) {
$tokenCredentials = unserialize($_SESSION['token_credentials']);
$user = $server->getUserDetails($tokenCredentials);
var_dump($user);
} elseif (isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])) {
$temporaryCredentials = unserialize($_SESSION['temporary_credentials']);
$tokenCredentials = $server->getTokenCredentials($temporaryCredentials, $_GET['oauth_token'], $_GET['oauth_verifier']);
unset($_SESSION['temporary_credentials']);
$_SESSION['token_credentials'] = serialize($tokenCredentials);
session_write_close();
header("Location: http://{$_SERVER['HTTP_HOST']}/twitter/auth?user=user");
exit;
} elseif (isset($_GET['denied'])) {
echo 'Hey! You denied the client access to your Twitter account!';
}
$temporaryCredentials = $server->getTemporaryCredentials();
$_SESSION['temporary_credentials'] = serialize($temporaryCredentials);
session_write_close();
$server->authorize($temporaryCredentials);
It turns out that I did not followed the 3-legged Oauth by twitter which is also indicated in the sample from the library.
In my code above, I've skipped the $server->authorize($temporaryCredentials) wherein it will show the Authorization Page/Login page of twitter.
I have a php application that use OAuth2 to authenticate users to their account.
until yesterday, everything worked very well.
But today, and without changing my code, when I try to access to my account, and after I authenticates to my google account, I obtain a blank page.
I debug the code and I found that it crashed when the Google_Client try to verifyIdToken and more exactly in the function verifySignedJwtWithCerts because : $segments = explode(".", $jwt); find 4 segments and not 3.
here is my code :
...
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
$client->setScopes("email");
if(!isset($_GET['code']))
header("Location: ".$client->createAuthUrl());
else
{
$client->authenticate($_GET['code']);
$_SESSION["access_token"] = $client->getAccessToken();
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
} else {
$authUrl = $client->createAuthUrl();
}
$ticket = $client->verifyIdToken();
if ($ticket) {
$admin = $ticket->getAttributes();
}
$_SESSION["email"] = $admin["payload"]["email"];
...
Can anyone offer an explanation?
Thank's in advance
Some how I didn't find any answer in Google. So I going to share what I do to make it work.
The short answer: Because the token you use in verifyIdToken() is invalid.
The long answer as below:
I'm not sure if it is the correct steps:
After Google Login Authentication, we will get the "Authorization
Code" from oauthplayground (for testing). Please enter your oauth client_id and oauth client secret in the setting before usage.
I have use the "Authorization Code" to get the other tokens by writing
$token = $client->fetchAccessTokenWithAuthCode("THE_AUTHORIZATION_CODE");
Inside $token, I have receive the following: access_token, token_type, expires_in, refresh_token, id_token, created.
Now use the id_token in $payload = $client->verifyIdToken(id_token);
Then you will get the correct information you needed like names, aud, exp, iss etc in $payload.
Note: To avoid your code return the "Wrong number of segments in token" error again, you have to try and catch the verifyIdToken method
try {
$payload = $client->verifyIdToken(id_token);
}
catch (Exception $e) {
echo "Invalid id token";
}
On my side, I've been working on MERN Application and, the issue was on the way I send the tokenId on the backend.
Check if the idToken you are sending to the backend is the same as the one you are getting on googleSuccess.
before.
const onGoogleSuccess = (response) => {
const tokenId = response.accessToken;//Wrong
console.log("SUCCESS::", response);
dispatch(login({ tokenId })).then((res) => {
console.log("GOOGLE-LOGIN::", res);
});
};
After:
before.
const onGoogleSuccess = (response) => {
const tokenId = response.accessToken;
console.log("SUCCESS::", response);
dispatch(login({ tokenId })).then((res) => {
console.log("GOOGLE-LOGIN::", res);
});
};
Accessing the Coinbase API used to be really simple: all you needed was an API key. Now you need something called a "nonce" and a "signature". I pass my new API "Secret", the nonce, and the Key in my request, but it returns an "invalid_key" error. What gives?
EDIT March 12th: Added a tutorial on interacting with the API via OAuth.
The fact that the API used to be so simple -- only needing a Key -- means it was pretty insecure. So they beefed up the security a week-ish ago. Here's the blog post:
http://blog.coinbase.com/post/75936737678/more-security-and-granular-control-with-the-new-api
Everyone now gets an API "Secret" in addition to an API Key. Whenever you make a request to the API, you have to include three parameters:
Your API Key.
A "nonce", which is a unique number that you use to identify something. In this case, every single request you make needs to have a new number, and each request's nonce has to be bigger than the one before it.
Your API "Signature". This is NOT your API "Secret".
The Signature is your nonce followed immediately by the full URL to which you're posting your request, parameters and all. This URL also contains the nonce, so the whole thing all together would look something like this:
12345https://coinbase.com/api/v1/buttons?nonce=12345&name=Socks&price=9.95
Then you take that whole thing and encode it as a "SHA256" hash. If you don't know what that means, don't panic -- you can do it in one line using a function PHP already has built in.
At any rate, I was having some trouble figuring all this out, so I spent a little while on it and put together this script, which makes GETing and POSTing to the API really easy. I'd love to hear people's thoughts!
<?php
function coinbaseRequest($what,$getOrPost,$parameters){
//Obviously, your API Key and Secret go here.
$apikey = "blahblahblah";
$apisecret = "blahblahblahblah";
$nonce = file_get_contents("nonce.txt") + 1;
file_put_contents("nonce.txt", $nonce, LOCK_EX);
$url = "https://coinbase.com/api/v1/" . $what . "?nonce=" . $nonce;
if($parameters != ""){
$parameters = http_build_query(json_decode($parameters), true);
}
//Here I go, hashing the Signature! Thanks, PHP, for making this easy!
$signature = hash_hmac("sha256", $nonce . $url . $parameters, $apisecret);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
"ACCESS_KEY: " . $apikey,
"ACCESS_NONCE: " . $nonce,
"ACCESS_SIGNATURE: " . $signature
)));
if($getOrPost == "post"){
curl_setopt_array($ch, array(
CURLOPT_POSTFIELDS => $parameters,
CURLOPT_POST => true,
));
}
$results = curl_exec($ch);
curl_close($ch);
echo $results;
}
//This is a POST example.
coinbaseRequest("buttons", "post", '{
"button": {
"name": "test",
"price_string": "1.23",
"price_currency_iso": "USD",
"variable_price": true
}
}');
//This is a GET example.
coinbaseRequest("account/balance", "get", false);
?>
Notes:
I tried using (microtime(true)*100) for my nonces. The problem is it makes a decimal number, and the last few digits kept getting dropped or rounded off so it didn't work. Then I thought, "Screw this", made a blank nonce.txt file, and wrote 1 in it, and to get nonces I just got the contents of that file, added 1, and replaced the file with the new number. It served a second purpose as a counter showing how many total requests I've made.
But then someone pointed out to me PHP's "uniqid" function, which generates an ID based on the current microtime. So you can also try this:
$nonce = hexdec(uniqid());
This has the advantage of not accessing an external file. I actually really like being able to see how many requests I've made, and so will probably stick with the (bad) nonce.txt method.
The coinbaseRequest() function has three parameters. The first is the directory to which you're making your request -- that is, whatever's supposed to come after "https://coinbase.com/api/v1/". The second parameter is "get" or "post", depending on whether it's a GET or a POST request. (Make sense?)
The third parameter is all the queries you're passing in your request. This should be formatted as JSON, unless it's a GET request that doesn't take any parameters (besides the Key, Nonce, and Signature which the function includes for you), in which case you should leave this as false.
EDIT, March 3rd:
I made a little function for taking whatever's returned by coinbaseRequest and turning it into a button:
function makebutt($data){
$data = json_decode($data,true);
$buttoncode = $data["button"]["code"];
return ("<a class=\"coinbase-button\" data-code=\"" . $buttoncode . "\" href=\"https://coinbase.com/checkouts/" . $buttoncode . "\">Pay With Bitcoin</a><script src=\"https://coinbase.com/assets/button.js\" type=\"text/javascript\"></script>");
}
YE GREAT OAUTH TUTORIAL
<?php
/*OAuth is great. It's also complicated. Or rather, it LOOKS complicated.
This whole script is just one big long function. It's a really, really ugly
function. I broke down everything "Barney-style" to demonstrate all the steps
in the process, and because there are some things you have to decide -- how to
record the user data, for instance.
Let's get this train wreck a rollin'.*/
function oauthRequest($apiPath,$getOrPost,$parameters){
/*You get this info from https://coinbase.com/oauth/applications*/
$clientId = "#####";
$clientSecret = "#####";
$callbackUrl = "http://www.blah.com/oauth.php";
function curling($url,$getpost,$params){
if($params != ""){
$params = http_build_query(json_decode($params), true);
}
if($getpost == "get"){
$ispost = false;
$url .= $params;
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true
));
if($getpost == "post"){
curl_setopt_array($ch, array(
CURLOPT_POST => $ispost,
CURLOPT_POSTFIELDS => $params
));
}
$results = curl_exec($ch);
curl_close($ch);
return $results;
}
/*There are two people involved here: the Client (you), and the User (the
person accessing your app or site).
You'll need 3 pieces of data for each user before your app can access their
Coinbase account: a User Code, an Access Token, and a Refresh Token.
For the purposes of this demonstration, I'm recording all of the user data in
a .txt file on my server. THIS IS PROBABLY A BAD IDEA in real life because .txt
files aren't secure at all, and this text file will only store the data for one
user (it gets overwritten every time). This is the kind of stuff you'd put in an
SQL database if you have one, or maybe in the user's cookies.*/
if(!file_exists("userdata.txt") || file_get_contents("userdata.txt") == ""){
file_put_contents("userdata.txt",json_encode(array(
"userCode" => "",
"accessToken" => "",
"refreshToken" => ""
)), LOCK_EX);
}
$userData = json_decode(file_get_contents("userdata.txt"), true);
/*Okay. So. First thing we're going to do is see if we have a User Code for
this user. These are big alphanumeric strings that are 64 characters long. If
we have one, it'll either be in the URL of this page (the $_GET array), or
it'll be in that userdata.txt file.*/
if(array_key_exists("code",$_GET) && $_GET["code"] != ""){
$userCode = $_GET["code"];
}else if(array_key_exists("userCode",$userData) && $userData["userCode"] != ""){
$userCode = $userData["userCode"];
}else{
/*If we don't have a User Code, then this next snippet of code will fire. It'll
return the link for a special user-specific Coinbase page to which the user
will need to go to authorize your app to access their Coinbase account (by
signing into Coinbase and clicking a green "Authorize" button).
After authorizing your app, they'll be automatically taken to the Redirect URL
you specified, with their User Code added to the end of the URL. So if your
Redirect URL is www.blah.com/oauth.php, they'll go to www.blah.com/oauth.php?
code=123451234512345 .
This User Code never expires, and so theoretically the user should only need to
go to the authorization link once. However, if you don't make a way of getting
the User Code in the future (my fancy "userdata.txt" in this case) or they de-
authorized your app from within their Coinbase account, then they'll need to go
to the link again and re-authorize your app from the beginning.
I have it set up so my Redirect URL and the rest of my OAuth script are all on
the same page: www.blah.com/oauth.php . So the user will just start back at the
beginning of this script, and THIS time the script will see the User Code in
the URL (the $_GET array), and so will skip this next bit.
Whew. You with me so far?*/
return ("https:/*coinbase.com/oauth/authorize?" . http_build_query(array(
"response_type" => "code",
"client_id" => $clientId,
"redirect_uri" => $callbackUrl
)));
die;
}
/*Here I am, recording the User Code for future use in userdata.txt*/
$userData["userCode"] = $userCode;
file_put_contents("userdata.txt",json_encode($userData),LOCK_EX);
/*Alright, we've got the User Code. Now we need the Access Token -- another 64-
character string. The difference is that the Access Token expires every 2 hours
(7200 seconds). Let's see if we already have one in the userdata.txt file.*/
if(array_key_exists("accessToken",$userData) && $userData["accessToken"] != ""){
$accessToken = $userData["accessToken"];
$refreshToken = $userData["refreshToken"];
}else{
/*If we're here, it's because we don't have an Access Token for this user. We
get one by making this POST request:*/
$authorization = json_decode(curling(
"https:/*coinbase.com/oauth/token" . "?" . http_build_query(array(
"grant_type" => "authorization_code",
"code" => $userCode,
"redirect_uri" => $callbackUrl,
"client_id" => $clientId,
"client_secret" => $clientSecret
)), "post", ""), true);
if(array_key_exists("error",$authorization)){
/*If something goes wrong here, I'm going to clean out userdata.txt and ask the
user to try again.*/
file_put_contents("userdata.txt","",LOCK_EX);
die("Something went wrong. Please refresh the page and try again.");
}
$accessToken = $authorization["access_token"];
$refreshToken = $authorization["refresh_token"];
}
/*The Refresh Token is what you use to get a new Access Token once the current
Access Token has expired. The Refresh Token never expires, but can only be used
once. Anytime you get an Access Token, you'll also be given a Refresh Token.
If you don't have the Refresh Token and a working Access Token for the user,
they'll need to re-authorize your app all over again.
I'm backing up the Access Token and Refresh Token to userdata.txt*/
$userData["accessToken"] = $accessToken;
$userData["refreshToken"] = $refreshToken;
file_put_contents("userdata.txt",json_encode($userData),LOCK_EX);
/*Alright! At this point, we should have the three bits of user data we need:
the User Code, the Access Token, and the Refresh Token. So now lets try
actually making an API request.
This whole script is really just one big function called "oauthRequest". You
pass three parameters to the function: the path of the API request (everything
after https:/*coinbase.com/api/v1/), whether this API query is a GET or a POST,
and any parameters that go along with that GET or POST request. These params
first come into play here.
Let's make the API request:*/
$results = curling("https:/*coinbase.com/api/v1/" . $apiPath . "?" . http_build_query(array(
"access_token" => $accessToken
)), $getOrPost, $parameters);
/*Now we're going to make sure the request actually worked, and didn't get
rejected because the Access Token was expired. If it WAS expired, the
results should be blank. (It'll return a 401 if you want to get fancy.)*/
$resultsArray = json_decode($results);
if(count($resultsArray) < 1){
/*Looks like it did expire, so now we make a POST request using the Refresh
token, which will return a new Access Token AND a new Refresh Token.*/
$reAuthorization = json_decode(curling(
"https:/*coinbase.com/oauth/token?" . http_build_query(array(
"grant_type" => "refresh_token",
"code" => $userCode,
"refresh_token" => $refreshToken
)), "post", ""), true);
$accessToken = $reAuthorization["access_token"];
$refreshToken = $reAuthorization["refresh_token"];
/*Let's back those up to userdata.txt...*/
$userData["accessToken"] = $accessToken;
$userData["refreshToken"] = $refreshToken;
file_put_contents("userdata.txt",json_encode($userData),LOCK_EX);
/*...and try the API request all over again:*/
$results = curling("https:/*coinbase.com/api/v1/" . $apiPath . "?" . http_build_query(array(
"access_token" => $accessToken
)), $getOrPost, $parameters);
/*If it doesn't work THIS time, I'm going to clean out userdata.txt and ask
the user to try again. One of the codes probably got all mungled up.*/
$resultsArray = json_decode($results);
if(array_key_exists("error",$resultsArray)){
file_put_contents("userdata.txt","",LOCK_EX);
die("Something went wrong. Please refresh the page and try again.");
}
}
/*If, however, everything went right, then this function will return the JSON
string with the data from the API! Hooray!*/
return $results;
}
/*Here are 4 different example requests you can make.*/
/*
echo oauthRequest("account/generate_receive_address","post","");
echo oauthRequest("buttons","post",'{
"button": {
"name": "test",
"type": "buy_now",
"price_string": ".01",
"price_currency_iso": "USD"
}
}');
echo oauthRequest("prices/buy","get",'{
"qty": 1,
"currency": "USD"
}');
echo oauthRequest("account/balance","get","");
*/
?>
It's not working because Coinbase recently implemented the OAuth2 protocol. This ensures the personal information of your user is transmitted securely. I referred to this implementation several months ago when writing my own OAuth class on another project:
I'm getting a TokenResponseException from Laravel when I try to login to my web site with Facebook using oauth-4-laravel.
OAuth \ Common \ Http \ Exception \ TokenResponseException
Failed to request resource.
Using Facebook's JavaScript API works like its supposed to, so I'm pretty sure my application is configured correctly.
Are there any known issues that might cause this problem? Am I doing something wrong, or is this a bug in the library?
With the exception of a redirect line that works around another bug, my code is identical to the example code at the GitHub page. I think the exception is thrown when I try to get the token from the Facebook Service object.
Here's the code:
public function loginWithFacebook() {
// get data from input
$code = Input::get( 'code' );
// get fb service
$fb = OAuth::consumer( 'Facebook' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from google, get the token
$token = $fb->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $fb->request( '/me' ), true );
$message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
echo $message. "<br/>";
//Var_dump
//display whole array().
dd($result);
}
// if not ask for permission first
else {
// get fb authorization
$url = $fb->getAuthorizationUri();
// return to facebook login url
// ref: https://github.com/artdarek/oauth-4-laravel/issues/27
//return Response::make()->header( 'Location', (string)$url );
return Redirect::to((string)$url);
}
}
And a screenshot:
I had this exact same problem. It turns out that my issue was that my return_uri was missing a trailing slash, which through off the entire process. Make sure that when you're calling it you've added it.
$fb = OAuth::consumer('Facebook','http://url.to.redirect.to/');
NOT
$fb = OAuth::consumer('Facebook','http://url.to.redirect.to');
first try to load file_get_contents("https://www.facebook.com");
if allow_url_fopen=0 was set in the php.ini it will not work so you need to change it to allow_url_fopen=1
The weirdest thing i have your problem with google not with facebook, so here is my code maby it helps you fix your fb problem
public function loginWithFacebook() {
// get data from input
$code = Input::get( 'code' );
// get fb service
$fb = OAuth::consumer( 'Facebook' );
// check if code is valid
// if code is provided get user data and sign in
if ( !empty( $code ) ) {
// This was a callback request from facebook, get the token
$token = $fb->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $fb->request( '/me' ), true );
$message = 'Your unique facebook user id is: ' . $result['id'] . ' and your name is ' . $result['name'];
echo $message. "<br/>";
//Var_dump
//display whole array().
dd($result);
}
// if not ask for permission first
else {
// get fb authorization
$url = $fb->getAuthorizationUri();
// return to facebook login url
return Redirect::to( (string)$url );
}
}
Since my previous answer was deleted.. Let's try again..
--
After some debugging I think I got it. Commenting out the error_reporting part visible in your code snippet will already tell you a lot. The file_get_contents call got a 401 Unauthorized because the tokens were no longer valid.
After changing code, start your auth process from the beginning and don't refresh your url half-way, that wil cause the error.
The problem should be here $token = $fb->requestAccessToken( $code );
When I tried var_dump it, I get this.
object(OAuth\OAuth2\Token\StdOAuth2Token)[279]
protected 'accessToken' => string 'your-accessToken' (length=180)
protected 'refreshToken' => null
protected 'endOfLife' => int 1404625939
protected 'extraParams' =>
array (size=0)
empty
Try this and check what you've get as accessToken. Anyway, your function loginWithFacebook working fine with me.
I had the same problem. I was trying to access facebook graph. It wasn't that it could not access the URL, it was that Facebook was returning a 400 error because I wasn't passing parameters through. Try connecting to HTTPS on a site that will have a working HTTPS connection. E.g. Try this:
file_get_contents("https://www.namhost.com");
If that works, you must see why the HTTPs connection you are connecting to is failing, because the problem isn't that you can't connect to HTTPs, but rather that what you are connecting to isn't liking the request.
I am using the following code to post to Facebook:
require('facebook.php');
$fb = new Facebook(array('appId' => 'MY APP ID','secret' => 'MY APP SECRET','cookie' => true));
$result = false;
$feed_dir = '/401868882779/feed/'; //to the UID you want to send to
$acToken = "MY ACCESS TOKEN";
$url = 'URL';
$link = $url . 'event.php?id=' . $id;
if (isset($picture))
{
$picture = $url . 'uploads/' . $picture;
}
else
{
$picture = $url . 'images/blank100x70.png';
}
$msg_body = array('access_token' => $acToken,'name' => $noe_unsecured,'message' => $link,'link' => $link,'description' => $description_unsecured,'picture' => $picture);
try
{
$result = $fb->api($feed_dir, 'post', $msg_body);
}
catch (Exception $e)
{
$err_str = $e->getMessage();
}
but I need to update the access token manually every time it changes. I am sure there's solution but I cant find it.. I tried lots of scripts and nothing worked.
It is possible.
Check: http://developers.facebook.com/docs/reference/php/facebook-setAccessToken/
Depending on when you perform the wall post, you might need to request the offline_access permission. This will convert your access_token into a format that does not expire so there would be no need to refresh the token.
A simple solution...remove the access_token!
You simply don't need it as long as you got the publish_stream permission!
I believe there are multiple methods to do this:
- you can use the method already provided in the PHP SDK getAccessToken which returns the current access token being used by the sdk instance, more info at this url.
- However you need not use an access token to call the api() method, once you ask the user for the publish_stream permission, as already mentioned by #ifaour. Hence you can do something like this example, scroll to the subheading Post a link to a User's wall using the Graph API.
- Then, you have another three options
i) either get a new access token using the method here, if you are posting when the user is currently using your app, otherwise you can try the next 2 options
ii) get offline access
iii) i'm not sure of this, but you might want to try with an app access token which can be obtained this way.