Laravel Shopify API Wrapper, refused the connection - laravel-5

I have a project on building a shopify app through "embedded SDK" The app was installed successfully but it does not redirect back to admin where the app should show the API call result. When I try to access the app that I installed the frame will just display The server refused the connection.
I used the joshrps/laravel-shopify-API-wrapper for my laravel project. This is my controller where I make a request to install the app http://pastebin.com/zEn96SWs , this is my redirect uri when the app is successfully installed:
Route::get('shopify',function(){
$sh = App::make('ShopifyAPI',[
'API_KEY'=>'a1568bd534e2e7a88b21d693bdc73afe',
'API_SECRET'=>'b15f951478db59369da196e77ea23fb7',
'SHOP_DOMAIN'=>'shinobishop.myshopify.com']);
$code = Input::get('code');
try`enter code here`
{
$accessToken = $sh->getAccessToken($code);
}
catch (Exception $e)
{
echo '<pre>Error: ' . $e->getMessage() . '</pre>';
}
));
I hope you can help me with this issue. Its my first time using shopify API on projects.

I think you need this in your controller:
$authorize_url = $sh->installURL([
'permissions' => array (
'write_orders', 'write_products'
),
'redirect' => 'https://dev.yourshopifystore.com/route/'
]);
return Redirect::to($authorize_url);

Related

Log-in users in flutter through social accounts with laravel-socialite backend

I am working on a flutter application, and I want to implement social login (Google and Facebook).
My API is implemented with Laravel and uses Laravel-socialite to authenticate users, there is the backend, web frontend (using VueJs) and now I am working on the mobile application using flutter.
The web application is working good (using the vue-social-auth package).
What I have done till now:
Used flutter_google_sign_in to handle authentication on the flutter app.
Did configure the package and I can successfully get user info through that package.
Problem I am facing:
What I don't seem to get working is to send the user that just logged in to the backend in order to provide an in-app user experience.
This is what the vue-social-auth package provides and what I send to the backend, which is working fine:
{code: "4/0AY0e-g442SMxdtLb_MVdQ63u1ydp48bbCRQco5Azoyf3y1rvYybDabyZGOvwAs7ZFJDQHA", scope: "email+profile+openid+https://www.googleapis.com/au…le+https://www.googleapis.com/auth/userinfo.email", authuser: "0", prompt: "consent"}
And this is what flutter_google_sign_in gives (aside of the user profile data:
idToken: "",
accessToken: "",
serverAuthCode: "",
serverAuthCode is always null.
How can I make it so that, using the same API logic, log-in users on flutter through social accounts?
Thank you.
Apparently, google sign in doesn't work on flutter except with Firebase/some cloud API backend service. I was using a local Laravel API for user auth so adding google sign in functionality requires setting up a firebase account/profile, downloading and adding the googleservices.json file to flutter project as explained in google_sign_in package installation manual. You also need to import firebase-auth package
Flutter Code (I use flutter modular pattern but same applies with Bloc/Provider if you get the idea as explained by Hamza Mogni above)
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<LoginResponseModel> googleLoginResponse() async {
String url = env['API_BASE_URL'] + '/api/auth/google';
//click on google sign in. Get accessToken from google through googlesignin
plugin.
//Send accessToken to socialite in backend to request/create user data
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
if (googleSignInAccount == null) {
print('Google Signin ERROR! googleAccount: null!');
return null;
}
GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
//this is user access token from google that is retrieved with the plugin
print("User Access Token: ${googleSignInAuthentication.accessToken}");
String accessToken = googleSignInAuthentication.accessToken;
//make http request to the laravel backend
final response =
await http.post(
url,
body: json.encode({"token": accessToken}),
headers: {"Content-Type": "application/json"});
if (response.statusCode == 200 || response.statusCode == 422) {
return LoginResponseModel.fromJson(
json.decode(response.body), // {'message':'Google signin successful'}
);
} else {
throw Exception('Failed to load data!');
}
}
For Logout function, you need to signout of both firebase and google account instance or you will always be logged in by the first known/used google account in subsequent login attempts.
Future<LogoutResponseModel> logout() async {
try {
await _auth.signOut();
await _googleSignIn.disconnect();
} catch (e) {
print('Failed to sign out ' + e.toString());
}
//api route to destroy sanctum token. santum token is added as authorization header
var url = env['API_BASE_URL'] + "/api/logout";
final response =
await http.post(Uri.tryParse(url), headers: {'Bearer ' $sanctumtoken});
if (response.statusCode == 200 || response.statusCode == 422) {
return LogoutResponseModel.fromJson(
json.decode(response.body),
);
} else {
throw Exception('Failed to load data!');
}
}
Laravel Code (route to controller method is api/auth/google, method expects to receive google access token from flutter app)
public function requestTokenGoogle(Request $request) {
// Getting the user from socialite using token from google
$user = Socialite::driver('google')->stateless()->userFromToken($request->token);
// Getting or creating user from db
$userFromDb = User::firstOrCreate(
['email' => $user->getEmail()],
[
'email_verified_at' => now(),
'first_name' => $user->offsetGet('given_name'),
'last_name' => $user->offsetGet('family_name'),
'avatar' => $user->getAvatar(),
]
);
// Returning response
$token = $userFromDb->createToken('Laravel Sanctum Client')->plainTextToken;
$response = ['token' => $token, 'message' => 'Google Login/Signup Successful'];
return response($response, 200);
}
I have solved it, after some digging I found out Laravel-Socialite has the functionality to log in users using their token built-in:
Quoting Socialite documentation:
If you already have a valid access token for a user, you can retrieve their details using Socialite's userFromToken method.

Google sign-in for websites: read user's phone number

I want to obtain users' phone numbers via Google sign-in on my website. In JavaScript for the "sign in with Google" button, I'm including scope 'https://www.googleapis.com/auth/user.phonenumbers.read' for permission to read the user's phone number. Maybe instead of this scope, I need to use 'https://www.googleapis.com/auth/contacts.readonly'. In any case, how do I obtain a signed-in user's phone number in PHP or JavaScript? When a user clicks on the sign-in button then because of the scope Google does ask permission to share a phone number. In Google API Console -> Edit app registration -> Scopes, I've included this phone number scope. Also, I've enabled People API in the Google project. I've installed
composer require google/apiclient
From the front end i'm receiving id-token for the signed-in user. My PHP is:
<?php
require_once 'vendor/autoload.php';
$id_token = $_POST['idtoken'];
$client = new Google_Client(['client_id' => '349001386451-bpovja3t7soabdu3cbhnig12fqlr20o0.apps.googleusercontent.com']);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
echo "Userid: $userid";
} else {
echo "Invalid ID token";
}
( The above code has been edited from https://developers.google.com/identity/sign-in/web/backend-auth )
I'm a newbie to this. I've got my client-id, client-secret and user's id-token. I'm able to show the userid in the above code, how to display the phone number?
Edit: I downloaded my client_secret.json and tried another method:
index.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfig('client_secret.json');
$client->setScopes(array('https://www.googleapis.com/auth/user.phonenumbers.read', 'https://www.googleapis.com/auth/contacts.readonly', 'profile'));
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_PeopleService( $client );
$optParams = ['personFields' => 'phoneNumbers'];
$profile = $service->people->get( 'people/me', $optParams );
var_export($profile);
var_export( $profile->getPhoneNumbers() );
} else {
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
--
oauth2callback.php
<?php
require_once __DIR__.'/vendor/autoload.php';
session_start();
$client = new Google\Client();
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php');
$client->addScope(Google_Service_PeopleService::USER_PHONENUMBERS_READ);
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
But when I'm running index.php it's giving error:
"error": { "code": 403, "message": "The caller does not have
permission to request "people/me". Request requires one of the
following scopes: [profile]."
But I do have included the profile scope in index.php
The phone number used for password reset will not be possible access:
It has been determined that we will not return the account recovery
phone number. The account recovery phone number is only intended for
specific usage like recovery the account when locked out. In the
interest of protecting user privacy this will not be returned in the
3rd party API.
I'm successfully getting phone number using a new 3rd method as given here:
https://developers.google.com/people/api/rest/v1/people/get?apix=true&apix_params=%7B%22resourceName%22%3A%22people%2Fme%22%2C%22personFields%22%3A%22phoneNumbers%22%7D
I copied the JavaScript code given in this link, removed all scopes except one, replaced YOUR_API_KEY and YOUR_CLIENT_ID, ran it on my server, in Firefox and it worked!
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for people.people.get
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/user.phonenumbers.read"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://people.googleapis.com/$discovery/rest?version=v1")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.people.people.get({
"resourceName": "people/me",
"personFields": "phoneNumbers"
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
But it only reads the phone number(s) added in Google account's "About me": https://myaccount.google.com/profile
And not the phone number of Google account which is used for password reset. I actually want this number but don't know whether possible.

Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature

I've been searching for this for hours, I hope someone here can help.
I built a subscription based site on Laravel and PayPal subscriptions using the PayPal PHP SDK.
Everything works perfectly except on thing:
I created a webhook for when a user cancels the payment on his end. I'm getting this error:
Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature.{"name":"VALIDATION_ERROR","message":"Invalid data provided","debug_id":"7225cebfec35a","information_link":"https://developer.paypal.com/docs/api/webhooks/#errors","details":[{"field":"webhook_id","location":"body","issue":"Required field cannot be blank"}],"links":[]}
Here is my code:
public function webhook()
{
/**
* Receive the entire body that you received from PayPal webhook.
*/
$bodyReceived = file_get_contents('php://input');
// Receive HTTP headers that you received from PayPal webhook.
$headers = getallheaders();
/**
* Uppercase all the headers for consistency
*/
$headers = array_change_key_case($headers, CASE_UPPER);
$signatureVerification = new \PayPal\Api\VerifyWebhookSignature();
$signatureVerification->setWebhookId(env('PAYPAL_WEBHOOK_ID'));
$signatureVerification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO']);
$signatureVerification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID']);
$signatureVerification->setCertUrl($headers['PAYPAL-CERT-URL']);
$signatureVerification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG']);
$signatureVerification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME']);
$webhookEvent = new \PayPal\Api\WebhookEvent();
$webhookEvent->fromJson($bodyReceived);
$signatureVerification->setWebhookEvent($webhookEvent);
$request = clone $signatureVerification;
try {
$output = $signatureVerification->post($this->apiContext);
} catch(\Exception $ex) {
//This is where it fails
print_r($ex->getMessage());
exit(1);
}
$verificationStatus = $output->getVerificationStatus();
$responseArray = json_decode($request->toJSON(), true);
$event = $responseArray['webhook_event']['event_type'];
if ($verificationStatus == 'SUCCESS')
{
switch($event)
{
case 'BILLING.SUBSCRIPTION.CANCELLED':
case 'BILLING.SUBSCRIPTION.SUSPENDED':
case 'BILLING.SUBSCRIPTION.EXPIRED':
case 'BILLING_AGREEMENTS.AGREEMENT.CANCELLED':
// $user = User::where('payer_id',$responseArray['webhook_event']['resource']['payer']['payer_info']['payer_id'])->first();
$this->updateStatus($responseArray['webhook_event']['resource']['payer']['payer_info']['payer_id'], 0,1);
break;
}
}
echo $verificationStatus;
exit(0);
}
And here is the $this->apiContext:
trait PayPalApiCredentialsTrait {
private $apiContext;
public function setCredentials()
{
$this->apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
env('PAYPAL_CLIENT_ID'), // ClientID
env('PAYPAL_CLIENT_SECRET') // ClientSecret
)
);
$this->apiContext->setConfig(
array(
'mode' => env("PAYPAL_MODE"),
'log.LogEnabled' => true,
'log.FileName' => '../PayPal.log',
'log.LogLevel' => 'INFO', // PLEASE USE `INFO` LEVEL FOR LOGGING IN LIVE ENVIRONMENTS
)
);
}
}
This is the error I get from the paypal.log:
[01-09-2020 15:54:18] PayPal\Core\PayPalHttpConnection : INFO: POST https://api.sandbox.paypal.com/v1/oauth2/token
[01-09-2020 15:54:18] PayPal\Core\PayPalHttpConnection : INFO: Response Status : 200
[01-09-2020 15:54:18] PayPal\Core\PayPalHttpConnection : INFO: POST https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature
[01-09-2020 15:54:19] PayPal\Core\PayPalHttpConnection : INFO: Response Status : 400
[01-09-2020 15:54:19] PayPal\Core\PayPalHttpConnection : ERROR: Got Http response code 400 when accessing https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature. {"name":"VALIDATION_ERROR","message":"Invalid data provided","debug_id":"26b12ee43cddd","information_link":"https://developer.paypal.com/docs/api/webhooks/#errors","details":[{"field":"webhook_id","location":"body","issue":"Required field cannot be blank"}],"links":[]}
I must mention that everything else works fine.
Creating plans, agreements, cancelling the both, showing active plans, and more...
Everything works smoothly.
This is the only thing that I can't seem to fix.
If anyone could figure this out for me, I'd really appreciate it.
Thank you!
The PayPal-PHP-SDK is deprecated and no longer maintained; it should not be used for new integrations. Its implementation of billing plans and subscriptions is old, and not compatible with the current version of the Subscriptions API.
In its place, a direct HTTPS integration (no SDK) should be used for Subscriptions, and for verifying webhooks.
(For the one time payment use case, there is a new v2 Checkout-PHP-SDK https://developer.paypal.com/docs/api/rest-sdks/ )

how to download file in ajax success using laravel response

i am making a zip file of PDFs and then download it in browser.. i have used ajax and want to receivce file in response so that i can download it.
return response()->download(public_path().'/documents/'.$zipName , $zipName, $headers);
this is the response i m getting
i have also tried this method but it didn't worked idont know what i am missing.
Laravel Response:
$downloadData = [
'zipFile' => $zipName,
'headers' => $headers,
'url' => public_path('documents/').$zipName
];
return response()->json(['status'=>1,'data'=> $downloadData]);
AJAX success:
var a = document.getElementById('zipDownload');
a.href = data.data.url;
a.target = '_blank';
a.download = data.data.zipFile;
setTimeout(function() {
a.click();
}, 200);
the anchor is showing correct path for the file and downloads when i paste that in a new tab.. but when i trigger the anchor tag it shows
Not allowed to load local resource: file:///C:/xampp/htdocs/ems/public/documents/records-20200512002210.zip
Try using this in the Laravel response (if you are accessing the web app using http://localhost:8000 or something similar, where the laravel app's public directory is set as the document root):
$downloadData = [
'zipFile' => $zipName,
'headers' => $headers,
'url' => '/documents/'.$zipName
];
return response()->json(['status'=>1,'data'=> $downloadData]);
Here you may even use the url('/documents/'.$zipName) or route() functions depending on the configurations/environment variables that have been set.
file:///C:/xampp/htdocs/ems/public/documents/records-20200512002210.zip is a file resource that is on the webserver, and the front-end (JS) should not see it.
So, the zip file that you are going to download should be accessed relative to the web application's URI.
In your case, if the browser is able to access something like http://localhost:8000/documents/<zip file name>.zip or http://localhost/ems/documents/<zip file name>.zip, then you're good to proceed further.

Google api php redirect_uri_mismatch

When using the following composer package bitgandtter/google-api for google php api client since I'm using it in combination with laravel 4 I get the following error redirect_uri_mismatch. My code looks like this(which is located under app/lib using the PSR-0 spec):
class Google {
private $client;
private $token;
public function __construct($code)
{
$this->client = new Google_Client();
$this->client->setApplicationName("camelCaseD");
$this->client->setClientId('SOMENUMBERS.apps.googleusercontent.com');
$this->client->setClientSecret('PRECIOUS');
$this->client->setRedirectUri('http://localhost:9000/auth/google');
$this->client->authenticate($code);
}
}
My routes are:
Route::group(['prefix' => 'auth'], function()
{
Route::post('google', function()
{
$postInput = file_get_contents('php://input');
try
{
$google = new Google($postInput);
} catch (Exception $e)
{
return Redirect::to('signin')->with('error', $e->getMessage());
}
});
});
I'm using the official google plus sign in button to log the user in then passing the authorization code to my server via $.ajax().
Here's what my api console settings look like:
I got that similar error. To resolve mine, I went to google console and reset the secret. I also made sure the Authorized JavaScript origins was set to the correct address.
http:// localhost :900/auth/google
is a directory or a page?
Maybe if it is a directory, the final url is different (like http:// localhost :900/auth/google/index.php) and Google does a control between 2 string, but they are different.

Resources