Performing requests to ETSY store allowing access automatically PHP OAUTH - php

I am using a library to connect to my ETSY store and pull data from receipts to bring them into my personal website (database).
After making the request using OAuth, I get to the ETSY site to "Allow Access"
https://www.etsy.com/images/apps/documentation/oauth_authorize.png
Then, I need to manually click on Allow Access and my request will be completed and will display the data requested.
I would like to avoid the process of manually clicking on "Allow Access", since I want my personal site to automatically display information pulled from ETSY orders.
Here is my current code for page etsyRequest.php:
$credentials = new Credentials(
$servicesCredentials['etsy']['key'],
$servicesCredentials['etsy']['secret'],
$currentUri->getAbsoluteUri()
);
// Instantiate the Etsy service using the credentials, http client and storage mechanism for the token
/** #var $etsyService Etsy */
$etsyService = $serviceFactory->createService('Etsy', $credentials, $storage);
if (!empty($_GET['oauth_token'])) {
$token = $storage->retrieveAccessToken('Etsy');
// This was a callback request from Etsy, get the token
$etsyService->requestAccessToken(
$_GET['oauth_token'],
$_GET['oauth_verifier'],
$token->getRequestTokenSecret()
);
// Send a request now that we have access token
$result2 = json_decode($etsyService->request('/receipts/111111'));
//echo 'result: <pre>' . print_r($result, true) . '</pre>';
echo $result2->results[0]->seller_user_id;
How could I automate the Allow Access part and get the returned value for my request by just running this page?

You can resolved this problem by simply save the returned "access token" and "token secret".
Steps to do it:
After making the request using OAuth, you get to the ETSY site to
"Allow Access". after allowing it will show a oauth_verifier pin.
After you enter this pin in your code it will set "access token" and
"token secret" to your request.you just need to save them in
variables or database.
next time when to create any request to etsy you just have to set
these access token" and "token secret" with your oauth_consumer_key
and oauth_consumer_secret. you don't need oauth_verifier pin at that time.
it will work util you revoke permission from your etsy account.
I did this in my java code because i mm facing same problem and its working.(sorry i m not good enough in php) here is my sample code may this helps-
public void accessEtsyAccount(String consumer_key, String consumer_secret, String requestToken, String tokenSecret, String shopName) throws Throwable{
OAuthConsumer consumer = new DefaultOAuthConsumer(
consumer_key, consumer_secret
);
if(StringUtils.isBlank(requestToken) || StringUtils.isBlank(tokenSecret) ){
OAuthProvider provider = new DefaultOAuthProvider(
"https://openapi.etsy.com/v2/oauth/request_token",
"https://openapi.etsy.com/v2/oauth/access_token",
"https://www.etsy.com/oauth/signin");
System.out.println("Fetching request token from Etsy...");
// we do not support callbacks, thus pass OOB
String authUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND);
System.out.println("Request token: " + consumer.getToken());
System.out.println("Token secret: " + consumer.getTokenSecret());
System.out.println("Now visit:\n" + authUrl
+ "\n... and grant this app authorization");
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(authUrl));
} catch (IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("xdg-open " + authUrl);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Enter the PIN code and hit ENTER when you're done:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String pin = br.readLine();
System.out.println("Fetching access token from Etsy...");
provider.retrieveAccessToken(consumer, pin);
} else {
consumer.setTokenWithSecret(requestToken, tokenSecret);
}
System.out.println("Access token: " + consumer.getToken());
System.out.println("Token secret: " + consumer.getTokenSecret());
URL url = new URL("https://openapi.etsy.com/v2/private/shops/"+shopName+"/transactions");
HttpURLConnection request = (HttpURLConnection) url.openConnection();
consumer.sign(request);
System.out.println("Sending request to Etsy...");
request.connect();
System.out.println("Response: " + request.getResponseCode() + " "
+ request.getResponseMessage());
System.out.println("Payload:");
InputStream stream = request.getInputStream();
String stringbuff = "";
byte[] buffer = new byte[4096];
while (stream.read(buffer) > 0) {
for (byte b: buffer) {
stringbuff += (char)b;
}
}
System.out.print(stringbuff);

You need to save the access token when you have requested the Etsy store for the first time and then the same access token can be used for later calls. This would prevent you from clicking ALLOW ACCESS again and again when requesting Etsy store through API.

Related

Php Firebase verification with Twitter get user information

I wan't to implement a Twitter login through the Firebase API.
My client is a android app who loggs into the Twitter account and sends the IdToken to my php backend. This works fine.
OAuthProvider.Builder provider = OAuthProvider.newBuilder("twitter.com");
provider.addCustomParameter("lang", "de");
FirebaseAuth.getInstance()
.startActivityForSignInWithProvider(/* activity= */ this, provider.build())
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
// User is signed in.
// IdP data available in
// authResult.getAdditionalUserInfo().getProfile().
// The OAuth access token can also be retrieved:
// authResult.getCredential().getAccessToken().
// The OAuth secret can be retrieved by calling:
// authResult.getCredential().getSecret().
Log.d("werte", "User is signed in");
Log.d("werte", "Username: " + authResult.getAdditionalUserInfo().getUsername());
Log.d("werte", "Info: " + authResult.getAdditionalUserInfo().getProfile().toString());
authResult.getUser().getIdToken(true).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult getTokenResult) {
Log.d("werte", "Accesstoken: " + getTokenResult.getToken());
}
});
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// Handle failure.
Log.d("werte", "Sign in failed");
e.printStackTrace();
}
});
But for php I only found a method to verify the token. I additionally need the user information. How do I get this?
$verifier = IdTokenVerifier::createWithProjectId('myProjectId');
try {
$token = $verifier->verifyIdToken($idToken);
echo($token);
} catch (IdTokenVerificationFailed $e) {
echo $e->getMessage();
// Example Output:
// The value 'eyJhb...' is not a verified ID token:
// - The token is expired.
}
Edit:
I solved it with the help of Frank. But I used a little different way.
$googleKeysURL = 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com';
$key = json_decode(file_get_contents($googleKeysURL), true);
$decoded = JWT::decode($idToken, $key, array("RS256"));
In the $decoded Object you can find every profile information you need.
Thank you Frank
Verifying the ID token does nothing more then what its name says: it verifies that the token is signed with a valid key.
If you want to use the claims from the decoded token, use a JWT decoding library like the one from Firebase: php-jwt. From the example in the documentation, you should be able to get the decoded token with:
$decoded = JWT::decode($jwt, $key, array('HS256'));

How can I reach users' calendar information on server?

Users authorize in my android application. And I am sending users' token and other information to my server. At this server I want to implement some logic for users.
I want to have exactly this flow.
I followed the steps quickstart.php in this link to get users' calendars on server.
But I get following error :
google oauth exception' with message 'could not json decode the token'
For this reason I tried this solution.
But i take same error. So as 3rd option I created the json format myself like in this solution as below.
$access_token = '{
"access_token":'.$access_token.',
"token_type":"Bearer",
"expires_in":3600,
"id_token":'.$id_token.',
"refresh_token":" ",
"created":'. time() .'
}';
as you see I do not know how to exchange refresh token . I searched how to get refresh token and saw this question. And implemented this solution to my code but nothing changed.
Edit 4 : I tried to get access token according to this answer at android application and send it to app server. I'm taking the code as before I did :
GoogleSignInAccount acct = result.getSignInAccount();
code = acct.getServerAuthCode();//sending this code to AsyncTask to get access token
my function to get Access Token:
private void getAccessToken()throws GoogleAuthException, IOException{
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
List<String> scopes = new LinkedList<String>();
scopes.add("https://www.googleapis.com/auth/calendar");
scopes.add("https://www.googleapis.com/auth/calendar.readonly");
scopes.add("https://www.googleapis.com/auth/urlshortener");
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(transport, jsonFactory, client_id, client_secret, scopes).build();
try{
GoogleTokenResponse res = flow.newTokenRequest(code).execute();
accessToken = res.getAccessToken();
}catch(IOException e){
}
at the php server side I changed user-example.php file little bit as below because I have the access token now:
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setAccessType("offline");
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/urlshortener");
$service = new Google_Service_Urlshortener($client);
if (isset($_REQUEST['logout'])) {
unset($_SESSION['access_token']);
}
$client->setAccessToken('{"access_token":"'. $access_token .'","token_type":"Bearer","expires_in":3600,"created":'. time() .'}');
if ($client->getAccessToken() && isset($_GET['url'])) {
$url = new Google_Service_Urlshortener_Url();
$url->longUrl = $_GET['url'];
$short = $service->url->insert($url);
$_SESSION['access_token'] = $client->getAccessToken();
But now I'm getting below error:
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST https://www.googleapis.com/urlshortener/v1/url: (403) Insufficient Permission' in C:\wamp\www\google-php\src\Google\Http\REST.php on line 110
I was getting Insufficient Permission error after I started to use GoogleAuthorizationCodeFlow to get access token as I mentioned in my OP. And then I tried to add Calendar scope to GoogleApiClient.Builder(this) but I get error like I can't add scope if I add Auth.GOOGLE_SIGN_IN_API because I had added Auth.GOOGLE_SIGN_IN_API to GoogleApiClient.Builder. So this time I tried to add the scope to GoogleSignInOptions.Builder and it is working now. I'm able to get both refresh token and access token. Below code solved my problem:
GoogleSignInOptions gso = state.getGso();
if(gso == null){
gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope("https://www.googleapis.com/auth/calendar"))
.requestIdToken(getString(R.string.server_client_id))
.requestEmail()
.requestServerAuthCode(getString(R.string.server_client_id), false)
.requestProfile()
.build();
}

Wrong number of segments in token (OAuth Google Api with php)

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);
});
};

How to use Service Accounts? Can i use my existing account at google as a service account?

So, i have two accounts at google, one is for personal use and one for company use. At the company account i have bought drive quota and it is at 200gb (i think), so im using it as a file storage cloud-server. My idea is to implement some of the files to the company website using google drive php api. As long as i know i can Use Application-Owned Accounts which sounds great, BUT i have to create new account it seems in order to use it with a regular account and if i want to use it with a server-side i will be not be able to use the company files at the regular account. So, im stuck at this situation!? Please, give me some advice. This is all new to me, so i need your help.
EDIT:
What it says from the link i posted above is this:
You may create a regular Google account like any user would, by going through the Google account sign-up flow or by creating an account on your Google Apps domain. Make sure it is then never used by an actual person but only by your application.
OK, but my account it is not new and it HAVE been used before. That mean that i will not be able to use my company account and if that is true, how can i achieve my goal?
i finally did it after days of researching how i can do this, here is a very simple code for how to obtain the access token and after you have it how to take the refresh token which you will need in order to access the user when he is in offline. I still have to understand how can i know when i store those values in the databse, how can i know that this user with the google id is the same user from the database and put the refresh token in the php, so the user dont have to authenticate again and he can do this only once (service account). So this simple code is using SESSIONS in order to store the access token and also the refresh token. It's not using database for the storage, but if you want when i figure out how this is done i can post the code here as well. So, here is the code:
<?php
session_start();
// Set error reporting
error_reporting(E_ALL | E_STRICT);
// Display errors
ini_set("display_errors", 1);
// require pages, you have to change it if your pages are somewhere else!
require_once 'src/Google_Client.php';
require_once "src/contrib/Google_Oauth2Service.php";
require_once "src/contrib/Google_DriveService.php";
/**
* Retrieved stored credentials for the provided user ID.
*
* #param String $userId User's ID.
* #return String Json representation of the OAuth 2.0 credentials.
*/
function getStoredCredentials($userId) {
if (!empty($_SESSION['userid'])) {
return $_SESSION['userid'];
}
}
/**
* Store OAuth 2.0 credentials in the application's database.
*
* #param String $userId User's ID.
* #param String $credentials Json representation of the OAuth 2.0 credentials to store.
*/
function storeCredentials($userId, $credentials) {
$_SERVER['userid'] = $userId;
}
/**
* Build a Drive service object.
*
* #param String credentials Json representation of the OAuth 2.0 credentials.
* #return Google_DriveService service object.
*/
function buildService($credentials) {
$apiClient = new Google_Client();
$apiClient->setUseObjects(true);
$apiClient->setAccessToken($credentials);
return new Google_DriveService($apiClient);
}
/**
* Send a request to the UserInfo API to retrieve the user's information.
*
* #param String credentials OAuth 2.0 credentials to authorize the request.
* #return Userinfo User's information.
* #throws NoUserIdException An error occurred.
*/
function getUserInfo($credentials) {
$apiClient = new Google_Client();
$apiClient->setUseObjects(true);
$apiClient->setAccessToken($credentials);
$userInfoService = new Google_Oauth2Service($apiClient);
$userInfo = null;
try {
$userInfo = $userInfoService->userinfo->get();
} catch (Google_Exception $e) {
print 'An error occurred: ' . $e->getMessage();
}
if ($userInfo != null && $userInfo->getId() != null) {
return $userInfo;
} else {
throw new NoUserIdException();
}
}
function retrieveAllFiles($service) {
$result = array();
$pageToken = NULL;
do {
try {
$parameters = array();
if ($pageToken) {
$parameters['pageToken'] = $pageToken;
}
$files = $service->files->listFiles($parameters);
$result = array_merge($result, $files->getItems());
$pageToken = $files->getNextPageToken();
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
$pageToken = NULL;
}
} while ($pageToken);
return $result;
}
function printFile($service, $fileId) {
try {
$file = $service->files->get($fileId);
print "Title: " . $file->getTitle();
print "Description: " . $file->getDescription();
print "MIME type: " . $file->getMimeType();
} catch (apiException $e) {
print "An error occurred: " . $e->getMessage();
}
}
// fill your details from the google console:
$client = new Google_Client();
$client->setApplicationName('***************');
$client->setScopes(array(
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'));
$client->setClientId('***************');
$client->setClientSecret('***************');
$client->setRedirectUri('***************/google-drive-api-php-client/serverside.php');
$client->setApprovalPrompt('force');
$client->setAccessType('offline');
$client->setDeveloperKey('***************');
// a simple code to check if the user have already login to the site and authenticate the site and if he does the site will not ask the user again for authentification and it will use the refresh token to "log" the user in
if (empty($_GET['code'])) {
// if the user visit the website for the first time he need to authentificate (redirecting the website to google)!
if (empty($_SESSION['access_token']) && !isset($_SESSION['refresh_token'])) {
header('Location: ' . $client->createAuthUrl());
// if the user have already visited the site, but the access token have expired use this code
} elseif (empty($_SESSION['access_token']) && isset($_SESSION['refresh_token'])) {
echo "refresh token1" . "<br>";
$google_token = json_decode($_SESSION['refresh_token'], true);
$client->refreshToken($google_token['refresh_token']);
$_SESSION['access_token']= $client->getAccessToken();
}
} elseif (!empty($_GET['code']) && empty($_SESSION['access_token'])) {
// if the user is visiting the website for the first time and dont have refresh token:
if (!isset($_SESSION['refresh_token'])) {
echo "access token" . "<br>";
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $_SESSION['access_token'];
// this will never execute, but i put it anyway :) if the user have already visited the site, but the access token have expired use this code (its the same as the above)
} elseif (isset($_SESSION['refresh_token'])) {
echo "refresh token2" . "<br>";
$google_token = json_decode($_SESSION['refresh_token'], true);
$client->refreshToken($google_token['refresh_token']);
$_SESSION['access_token']= $client->getAccessToken();
}
}
// if the access token have expired use the refresh token to gain access instead:
if ($client->isAccessTokenExpired()) {
$google_token = json_decode($_SESSION['refresh_token'], true);
$client->refreshToken($google_token['refresh_token']);
$_SESSION['access_token']= $client->getAccessToken();
}
// unset the sessions for testing:
// unset($_SESSION['access_token']);
// unset($_SESSION['refresh_token']);
// get some info from the user Google API like the file info
if (!empty($_SESSION['access_token'])) {
// create the service in this case Google Drive
$service = buildService($_SESSION['access_token']);
// mark the file ID
$fileid = "*******************";
// print the access token
echo "<pre>";
print_r(getUserInfo($_SESSION['access_token']));
echo "</pre>";
// print file metadata from google drive
// echo "<pre>";
// print_r(printFile($service, $fileid));
// echo "</pre>";
}
// printing the session for testing...
echo "<pre>";
print_r($_SESSION);
echo "</pre>";
// print the refresh token for testing
print_r($_SESSION['refresh_token']);
// print echo to see if the code is executing till the end or there is a fatal error someone in the code :)
echo "string";
?>

Zend Youtube API - Upload Videos on a Single Account?

I want to allow anyone register on my site, to upload their videos on my own youtube user channel.
I don't want them to comment any videos, or anything that requires their own login credentials.
Should I use: ClientLogin authorization ?
If so, how can I get a token so that I can allow my site to interact with my youtube channel account?
Any lights here will be greatly appreciated, since I'm kinda lost here.
I have accomplished this using ClientLogin. A basic class is below. This class returns an instance of Zend HTTP Client that is ready to make authenticated requests.
<?php
class GoogleAuthenticator {
public static function authenticate($logger) {
$tokenObj = new Token();
try {
$token = $tokenObj->get($token_name);
if(!empty($token)) {
//load a new HTTP client with our token
$logger->info('Using cached token: ' . $token);
$httpClient = new Zend_Gdata_HttpClient();
$httpClient->setConfig(array(
'maxredirects' => 0,
'strictredirects' => true,
'useragent' => 'uploader/v1' . ' Zend_Framework_Gdata/' . Zend_Version::VERSION
)
);
$httpClient->setClientLoginToken($token);
//attempt to use our token to make an authenticated request. If the token is invalid
// an exception will be raised and we can catch this below
$yt = new Zend_Gdata_YouTube($httpClient, 'uploader/v1', '', $youtube_api_key);
$query = new Zend_Gdata_YouTube_VideoQuery();
$query->setFeedType('top rated');
$query->setMaxResults(1);
$yt->getPlaylistListFeed(null, $query); //ignore the response!
} else {
$logger->info('Generating new HTTP client');
// Need to create a brand new client+authentication
$authenticationURL= 'https://www.google.com/youtube/accounts/ClientLogin';
$httpClient =
Zend_Gdata_ClientLogin::getHttpClient(
$username = YOUTUBE_USERNAME_PROD,
$password = YOUTUBE_PASSWORD_PROD,
$service = 'youtube',
$client = null,
$source = 'uploader/v1',
$loginToken = null,
$loginCaptcha = null,
$authenticationURL);
// get the token so we can cache it for later
$token = $httpClient->getClientLoginToken();
$tokenObj->destroy($token_name);
$tokenObj->insert($token, $token_name);
}
return $httpClient;
}catch(Zend_Gdata_App_AuthException $e) {
$tokenObj->destroy($token_name);
die("Google Authentication error: " . $e->getMessage());
}catch(Exception $e) {
$tokenObj->destroy($token_name);
die("General error: " . $e->getMessage());
}
} // authenticate()
} // GoogleAuthenticator
?>
You'll need to have these constants defined:
YOUTUBE_USERNAME_PROD
YOUTUBE_PASSWORD_PROD
Or modify the class to pass them in. The try/catch is needed because tokens can expire, so you need to a way to refresh them. Also, you need to make a dummy request to ensure the Token is valid even after you create it.
Keep in mind that YouTube (well, as of 2 years ago or so) prevented you from uploading a video more of than every 10 minutes, which makes your use-case pretty difficult. That is, you cannot allow multiple videos being uploaded on a single accounts behalf, more of than every 10 min. But YouTube might have lifted this since then. Good luck
Since I didn't find any complete solutions for API V3 in the documentation I've been exploring the Internet for a solution. In the end I ported the Python example to PHP and wrote a blog post about it for other people that have the same problem:
Uploading a video to youtube through api version 3 in PHP
This blogpost uses the Youtube V3 api with OAuth2 so you don't have to worry about it being deprecated. All other functions (ClientLogin, AuthSub and OAuth 1.0) in V2 are all deprecated as of April 20, 2012.

Categories