I use parse-php-sdk.Now I need my customers login with twitter then add them as parse users.Because there is no function I can use as twitter logining in ParseUser.php, so I write one:
public static function logInWithTwitter($id, $access_token, $expiration_date = null)
{
if (!$id) {
throw new ParseException("Cannot log in twitter user without an id.");
}
if (!$access_token) {
throw new ParseException(
"Cannot log in twitter user without an access token."
);
}
if (!$expiration_date) {
$expiration_date = new \DateTime();
$expiration_date->setTimestamp(time() + 86400 * 60);
}
$data = json_encode(['authData' =>
["twitter" => [
"id" => $id, "access_token" => $access_token,
"expiration_date" => ParseClient::getProperDateFormat($expiration_date)
]]
]);
$result = ParseClient::_request("POST", "/1/users", "", $data);
$user = new ParseUser();
$user->_mergeAfterFetch($result);
$user->handleSaveResult(true);
ParseClient::getStorage()->set("user", $user);
return $user;
}
But when I finished login with twitter, error occurs: Code : 251 Message:Twitter credential verification failed.. I try to look for solutions, but all I found are things about apps platform problems, and they can fix if by setting consumerKey and consumerSecret in TWSignedRequest. But I don't know whether I need to set twitter consumerKey and consumerSecret, if I need to do this ,where should I set?
Related
I'm using v5.0 of Facebook's PHP SDK and have already set up an app.
I would like to get a list of friends via the Graph API using the SDK. To illustrate my implementation, this is the code in which I am trying to get lists of friends on Facebook:
public static function getFriends($access_token)
{
$facebook_app_id = env('FACEBOOK_APP_ID');
$facebook_app_secret = env('FACEBOOK_APP_SECRET');
$facebook = new Facebook([
'app_id' => $facebook_app_id,
'app_secret' => $facebook_app_secret,
'default_access_token' => $access_token,
'default_graph_version' => env('FACEBOOK_API_VERSION') // v2.7
]);
try {
$facebook_request = $facebook->get('me/taggable_friends');
$friends = $facebook_request->getGraphEdge();
$all_friends = $friends->asArray();
if ($facebook->next($friends)) {
while ($friends = $facebook->next($friends)) {
$all_friends = array_merge($friends->asArray(), $all_friends);
}
}
return $all_friends;
} catch (\Exception $e) {
throw $e;
}
}
When the above method is called, it shows a Invalid appsecret_proof provided in the API argument exception message. Digging around, I read that passing a separate parameter of appsecret_proof will get rid of this, however, I've already tried using the App Token of my app taken from the Access Token Tool page to get the value for the appsecret_proof and I still get the error.
And to add, the Require App Secret in my app settings is set to No and yet I still get the same error. Am I missing anything or am I passing the wrong values in getting appsecret_proof?
I'm trying to get access to a rest API using the Authorization Code Flow with Laravel and Guzzle.
They specify the requirements:
GET https://api.restsite.com/oauth2/authorize ?
client_id = [application id] &
response_type = code &
scope = orders inventory &
redirect_uri = [redirect uri]
In Laravel I achieved it as such:
// Create a client
$client = new Client();
$request = $client->createRequest(
'GET', 'https://api.restsite.com/oauth2/authorize',[
'query' => [
'client_id' => 'myclientid',
'response_type' => 'code',
'scope' => 'inventory',
'redirect_uri' => 'https://myownsite/uri.php',
],
]
);
// Send the request
$response = $client->send($request);
If I print_r the $response it will show a login page from their site.
Now, their next instruction is upon successful login it will go to my redirect uri as such:
https://[redirect uri]?code=[authorization code]
With this authorization code I can now make another call by their instructions:
POST https://api.restsite.com/oauth2/token ?
grant_type = authorization_code &
code = [authorization code] &
redirect_uri = [redirect uri]
And finally if all is well the JSON response should look as such:
{
"access_token": [access token],
"token_type": "bearer",
"expires_in": 3600
}
Which I can use to access the protected resources at another endpoint.
Now where I'm stuck is in Laravel, after Guzzle makes the first call for the "authorize" endpoint the $response that comes back I wasn't sure what to do with it as I wasn't being automatically redirected anywhere.
So what I temporarily did was added this return view:
return View::make('welcome')->with('response', $response);
That's fine an dandy (looks ugly no css since not actually from their site) but seems to have proper form code when I look at the source.
The current URL is just my project root:
http://myserver:8080/test/public/
However, after I try to login I get redirected to my main root folder of the server:
http://myserver:8080/
I'm not sure how to get it to at least load the redirect URI properly so I can take that URI ?code= parameter and use it to make another call as required.
I hope I didn't loose anyone so far. Thanks in advance!
What I did was instead of using Guzzle to process the authorization initial step from an external site I simply did one of these:
Controller:
return redirect::to('https://api.restsite.com/oauth2/authorize?');
View:
Approve App
I had my redirect uri/callback return to my app to then use Guzzle to post and retrieve the necessary tokens which comes back as a json response so no need for any more external site/redirects.
Finally after all this I can use the actual resource endpoints to query for data.
UPDATE
Upon request I have provided a bit more detail on how the process goes:
View (authtoken.blade.php):
Request New Token
return_uri.php (http://myownsite.com/)
<?php
ob_start();
$url = 'http://myserver:8080/test/public/authtoken/get';
date_default_timezone_set('America/Los_Angeles');
$authcode = $_GET['code'];
echo 'Authorization code: ' . $authcode;
sleep(15);
$servername = "xx.xxx.xxx.xx";
$username = "user";
$password = "pass";
$dbname = "ca";
$now = date("Y-m-d H:i:s");
if ($authcode) {
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "INSERT INTO credentials (id, auth, authDate)
VALUES ('1','$authcode', '$now') ON DUPLICATE KEY UPDATE auth = values(auth), authDate = values(authDate) ";
if ($conn->query($sql) === TRUE) {
echo "Auth code created successfully";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
//echo '<br><br>go back';
while (ob_get_status())
{
ob_end_clean();
}
header( "Location: $url" );
}
?>
Controller
public function authtokenget()
{
$creds = Credentials::find(1);
$auth = $creds->auth;
$client = new Client();
$client->setDefaultOption('verify', false);
$data = 'grant_type=authorization_code&code=$auth&redirect_uri=https://myownsite.com/return_uri.php';
$data_string = json_encode($data);
$datlen = strlen($data_string);
$request = $client->createRequest(
'POST', 'https://api.restsite.com/oauth2/token',[
'headers' => [
'content-type' => 'application/x-www-form-urlencoded',
'content-length' => $datlen,
],
'body' => $data_string,
'auth' => ['xxxxx=', 'xxxxx'],
]
);
$response = $client->send($request);
}
RECAP
Access the authorize initial endpoint using a link in View.
Have a php return file that's part of the request to grab necessary token/access credentials and store to a database then return to a route.
The route runs a controller function which now grabs the data from the database entry you saved earlier to do as you wish now.
I'm using the Artdarek package to log in using google accounts and need to authorise the user for the app.
I'm using Laravel 4.2
This is the code from my function
public function loginWithGoogle() {
// get data from input
$code = Input::get( 'code' );
// get google service
$googleService = OAuth::consumer( 'Google' );
// 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 = $googleService->requestAccessToken( $code );
// Send a request with it
$result = json_decode( $googleService->request( 'https://www.googleapis.com/oauth2/v1/userinfo' ), true );
// Check to see if user already exists
if($user = User::where('email', '=', $result['email'])->first())
{
$user = User::find($user['id']);
Auth::login($user);
// If user isn't activated redirect them
if ($user->deactivated == 0)
{
return View::make('dashboard')->with('user', $user);
}
return Redirect::back()->withErrors(['Sorry You have not been approved', 'Speak to your manager']);
}
else
{
// Create new user waiting for approval
$new_user = new User();
$new_user->email = $result['email'];
$new_user->first_name = $result['given_name'];
$new_user->surname = $result['family_name'];
$new_user->googleID = $result['id'];
$new_user->deactivated = 1;
$new_user->save();
return Redirect::back()->withErrors(['Your account have been created. It is awaiting activation by your manager']);
}
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to google login url
return Redirect::to( (string)$url );
}
}
When a new user grants permission for the app, I get the error 'Cannot redirect to an empty URL'
For some reason my redirectURL is empty.
Take a look at document you will find out that you have to set redirect url at 2nd arguments in OAuth::consumer method.
https://github.com/artdarek/oauth-4-laravel#usage
It means, you should use consumer with 2 arguments instead of 1 arguments
$googleService = OAuth::consumer("google","https://mydirectlink");
I am following the docs from link below:
https://developers.google.com/+/mobile/android/sign-in#enable_server-side_api_access_for_your_app
Specifically the part that says:
If you do not require offline access, you can retrieve the access token and send it to your server over a secure connection. You can obtain the access token directly using GoogleAuthUtil.getToken() by specifying the scopes without your server's OAuth 2.0 client ID. For example:
I retrieve the access token like this:
accessToken = GoogleAuthUtil.getToken(
AuthenticatorActivity.this,
Plus.AccountApi.getAccountName(Common.mGoogleApiClient),
"oauth2:https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/plus.login email"
);
After I retrieve the access token I send it to a web server, on the web server i can see that it's a valid access token by calling
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$_POST['google_access_token']
The request above returns the android apps client id, it also returns the users email correctly.
The problem is that when I try to run $client->authenticate($_POST['google_access_token']); I get an exception with the message: "invalid_grant: Incorrect token type".
To prevent getToken caching I always invalidate the token in android app:
if (accessToken != null && !accessToken.isEmpty()) {
GoogleAuthUtil.invalidateToken(AuthenticatorActivity.this, accessToken);
}
Here's the php code:
if (!isset($_POST['google_access_token'])) {
throw new Exception('missing google_access_token');
}
$client = new \Google_Client();
$client->setApplicationName("GiverHub");
$client->setClientId($this->config->item('google_client_id'));
$client->setClientSecret($this->config->item('google_client_secret'));
$client->setDeveloperKey($this->config->item('google_developer_key'));
$client->setRedirectUri($this->config->item('google_redirect_uri'));
$client->setScopes([
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.me',
'email',
]);
try {
$client->authenticate($_POST['google_access_token']); // if i remove this the rest of the code below works! ...
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.$_POST['google_access_token'];
$req = new \Google_Http_Request($reqUrl);
$io = $client->getIo();
$response = $io->executeRequest($req);
$response = $response[0];
$response = json_decode($response, true);
if ($response === null) {
throw new Exception('Failed to check token. response null');
}
if ($response['issued_to'] !== '466530377541-s7cfm34jpf818gbr0547pndpq9songkg.apps.googleusercontent.com') {
throw new Exception('Invalid access token. issued to wrong client id: '. print_r($response, true));
}
if (!isset($response['user_id'])) {
throw new Exception('Missing user_id');
}
if (!isset($response['email'])) {
throw new Exception('Missing email');
}
/** #var \Entity\User $user */
$user = Common::create_member_google([
'id' => $response['user_id'],
'email' => $response['email'],
'given_name' => '',
'family_name' => '',
]);
$user->login($this->session);
if ($user instanceof \Entity\User) {
echo json_encode( [ 'success' => true, 'user' => $user ] );
} else {
echo json_encode( [ 'success' => false, 'msg' => $user ] );
}
} catch(Exception $e) {
echo json_encode(['success' => false, 'msg' => $e->getMessage()]);
}
The above code works if i remove the $client->authenticate(); line ... The problem is that I can't get the given_name / family_name etc .. only email / google_user_id from the tokeninfo ...
Any thoughts about why the key works for tokeninfo but not for authenticate?
I have tried many different variations of the scopes .. both on the server side and the android side ..
The $client->authenticate() method doesn't quite do what you're trying to do. It takes a one-time code from an earlier OAuth transaction and exchanges it for the access token. In your case - you're saying you already have the access token.
You should be able to call $client->setAccessToken() to set the token instead, so it may look something like
$client->setAccessToken($_POST['google_access_token']);
This is the solution I came up with after user158443 suggested I use $client->setAccessToken();
// first json_encode the access token before sending it to $client->setAccessToken();
$json_encoded_access_token = json_encode([
'access_token' => $_POST['google_access_token'],
'created' => time(), // make up values for these.. otherwise the client thinks the token has expired..
'expires_in' => time()+60 // made up a value in the future...
]);
// and then set it
$client->setAccessToken($json_encoded_access_token);
// and then get userinfo or whatever you want from google api !! :)
$oauth2 = new \Google_Service_Oauth2($client);
$user_info = $oauth2->userinfo->get();
NOTE: it's probably not smart to "emulate" the expires_in and created that i just did if you are in production ... You should probably call tokeninfo first and get the expires time from there...
NOTE: I still have no idea how to get a refresh token for this... but I don't need one for my use case..
I am using Artdarek's lib for Laravel but I have a problem.
when users try to login with Twitter they are redirected to Twitter authenticate page and asked for permission.
But if they authorize that app Twitter redirects them to page
"Redirecting you back to the application. This may take a few moments."
and then redirect back to authenticate page on Twitter.
authenticate?oauth_token=UNbRevLchuLCYxsDlgqHODQMmA4osBHoOKbzPLdkCs
Here is my config app/config/packages/artdarek/oauth-4-laravel/config.php
'storage' => 'Session',
'consumers' => array(
'Twitter' => array(
'client_id' => 'xxxxxxAPI key',
'client_secret' => 'xxxxxxAPI secret'
)
)
and here is my login function
public function twiiter() {
$code = Input::get('code');
$oauth_verifier = Input::get( 'oauth_verifier' );
$twitterService = OAuth::consumer('Twitter');
if(!empty($code)) {
$token = $twitterService->getStorage()->retrieveAccessToken('Twitter');
$twitterService->requestAccessToken( $code, $oauth_verifier, $token->getRequestTokenSecret() );
$result = json_decode( $twitterService->request( 'account/verify_credentials.json') );
$user = User::where( [ 'twitter_id' => $result->id ] )->first();
if ( $user ) {
$user->twitter_id = $result->id;
$user->save();
Auth::login($user);
return Redirect::to('/');
} else {
}
} else {
$token = $twitterService->requestRequestToken();
$url = $twitterService->getAuthorizationUri(['oauth_token' => $token->getRequestToken()]);
return Redirect::to((string)$url);
}
}
How to fix this problem? I checked in apps.twitter and my app can Sign in with Twitter, where did I made mistake?
I believe Twitter doesn't use the code variable, rather just the oauth_token which you see in the redirection url.
Here's the official example for Twitter, notice this line specifically:
if (!empty($_GET['oauth_token'])) {
So the reason you keep getting redirected is because no code querystring key is ever set, and therefore it keeps retrieving an access token etc.