Not receiving notifications from webhook - laravel & shopify - php

I am creating an app for merchants and Shopify using laravel. I have configured and installed webhooks to send admins notifications when new customers are created in config/shopify.php in my app.
shopify.php
use Oseintow\Shopify\Facades\Shopify;
use Laravel\Socialite\Facades\Socialite;
use App\User;
use App\Store;
use App\UserProvider;
use Auth;
$shopifyUser = Socialite::driver('shopify')->stateless()->user();
$shopUrl = $shopifyUser->nickname;
$accessToken = $shopifyUser->token;
Shopify::setShopUrl($shopUrl)->setAccessToken($accessToken)->post("admin/webhooks.json",
[
'webhook' =>
['topic' => 'customers/create',
'address' => 'https://shopify.kast.com/webhook',
'format' => 'json'
]
]);
Route
Route::post('/webhook', 'ReceiverController#webhook');
ReceiverController
public function webhook()
{
send sms/email to admin
}
Now when I configure the webhook in the shop admin settings and send a test notification or create a customer,I receive the SMS/emails
But when I delete the webhook settings from the admin page and create a new customer for the shop, I don't receive the SMS.
Is there any error in shopify.php (webhook configuration) for my app?
PS: shop domain is founz.myshopify.com and app is hosted https://shopify.kast.com

Most probably you didn't register a webhook using access token.
If you're using Oseintow\Shopify, your shopify.php file should look like:
<?php
return [
'key' => env("SHOPIFY_APIKEY", '0f20e4692981aefb8558etrgrh72thty5'),
'secret' => env("SHOPIFY_SECRET", 'fgghg55666585f1a09214drtg56454g')
];
Let it just holds your public app's credentials.
It looks like you haven't registered any webhook using access token. When you register a webhook using shopify admin, that webhook will be fired to all application. Don't do that unless you know what you're doing.
Instead try registering the same webhook using Postman with your access token and see if it is working. And then use your programming skills to automate it. Cheers!

There Can be two main reason for that.
1) Webhook could not created successfully. to check this Please make API call with
GET Request
GET /admin/api/2019-10/webhooks.json
If you did not get your desired webhook in the response please create it
2) In Laravel spacific development,you need to bypass VerifyCsrfToken middle-ware for your webhook route
as Laravel will not allow & blocks cross site requests default.to do so please follow below steps.
Go to app/http/middleware/VerifyCsrfToken & add your route in the $except array.
As Example :
protected $except = [
'/app/uninstalled-webhook-shopify/*',
'/products/create-webhook-shopify/*',
];

Related

Twinfield API OAuth2.0 getaccessToken php-twinfield/twinfield

I am currently trying to setup the Twinfield API, it should be pretty straight forward when using the php-twinfield/twinfield library. But there is one thing I don't fully understand.
Here is my code:
$provider = new OAuthProvider([
'clientId' => 'someClientId',
'clientSecret' => 'someClientSecret',
'redirectUri' => 'https://example.org/'
]);
$accessToken = $provider->getAccessToken("authorization_code", ["code" => ...]);
$refreshToken = $accessToken->getRefreshToken();
$office = \PhpTwinfield\Office::fromCode("someOfficeCode");
$connection = new \PhpTwinfield\Secure\OpenIdConnectAuthentication($provider,
$refreshToken, $office);
The $accessToken require something on the dots, some sort of code. I am not sure what that should be...
I hope someone can help me out. Thanks already!
I am still stuck with oauth2 setup... the provider seems to have all the information it needs to have. It returns a code which is needed to retrieve an accessToken. But, trying to get one using the following code:
$accessToken = $provider->getAccessToken('authorization_code',
['code' => $_GET['code']]);
This will return 'invalid_grant'.
I have tried to reset my clientSecret... but that did not help.
I hope somebody can help me any further.
To access the Twinfield API the users must be authenticated. You can either do this by specifying a username and password or using OAuth2. When using OAuth2 you delegate the authentication to a so called OAuth Provider. After the user authenticated, the provider will redirect the user's browser to an endpoint (redirectUri) at your application. That request, that your application receives, has a GET parameter called code. Your app will then exchange the code for a token using its clientId and clientSecret and HTTP POST. Which means that your application must be registered at the OAuth2 provider so that the provider (e.g. github, facebook, google, ...) can validate the client credentials and return a token. And you will have to configure your provider variable to point to the OAuth provider that you connect with.
$provider = new OAuthProvider([
'clientId' => 'XXXXXX', // The client ID assigned to you by the provider
'clientSecret' => 'XXXXXX', // The client password assigned to you by the provider
'redirectUri' => 'https://example.com/your-redirect-url/',
'urlAuthorize' => 'https://login.provider.com/authorize', //where the user's browser should be redirected to for triggering the authentication
'urlAccessToken' => 'https://login.provider.com/token', //where to exchange the code for a token
'urlResourceOwnerDetails' => 'https://login.provider.com/resource' //where to get more details about a user
]);
// If we don't have an authorization code then get one
if (!isset($_GET['code'])) {
// Fetch the authorization URL from the provider
// Redirect the user to the authorization URL.
}
Twinfield makes use of league/oauth2-client library for implementing OAuth. Therefore, refer to https://oauth2-client.thephpleague.com/usage/ for the details on how to setup an OAuth client in the twinfield library. league/oauth2-client supports some providers out of the box and allows third-party providers. Your provider may be in any of the lists. If not, refer to the documentation of your provider to get the right URLs.

Can't get Auth object and cookies by consuming my own Laravel API

I'm currently trying to build a secure SPA application in Laravel by using :
Laravel 5.6
Laravel Passport
Guzzle client
To make the whole application secure, I created a proxy to prefix all requests to the API and :
User the password grand type of token
Hide the client ID
Hide the client secret
Add automatic scopes based on the role of the user
This is how the Proxy works :
// The proxify endpoint for all API requests
Route::group(['middleware' => ['web']], function ()
{
Route::any('proxify/{url?}', function(Request $request, $url) {
return Proxify::makeRequest($request->method(), $request->all(), $url);
})->where('url', '(.*)');
});
Each time a request is made, it goes through that package I built to create the access token, refreshing it, or deleting it.
To create the access token for the user I'm using a MiddleWare at loggin :
$response = $http->post('http://myproject.local/proxify/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'username' => $request->get('email'),
'password' => $request->get('password'),
]
]);
This is working well, excepting the fact that I'm setting cookies in the Proxify::makeRequest, so I have to create them in the call, return them in the $response, and then at the end of the Middleware, attaching them to the request (Cookie::queue and Cookie::Make are not working in a Guzzle call it seems).
The access token is created and stored in a cookie.
First problem is that in this call, even in the middleware, and especially in that URL http://myproject.local/proxify/oauth/token, I don't have any access to the Auth trait, even if it's specified as a middleware attached to the route, so impossible to fetch information from the authenticated user.
Then the other problem is that when I'm making a call to get a ressource API such as :
$http = new Client();
$response = $http->get('http://myproject.local/proxify/api/continents');
$continents = $response->getBody()->getContents();
return view('dashboard')->with("continents", $continents);
In that case, when I'm calling the URL, the proxy is not able to get the access_token defined in the cookie with the CookieFacade through the HTTP call, neither the Auth object I'm whiling to use. The $_COOKIE variable is not working neither.
What is wrong with my structure so that I don't have any access to the cookie even if it's set and in the browser ? Any other way to get the info ? I tried to get the cookie from the request in the proxy, not working.
Have you tried using the Illuminate or Symfony Request classes and handling the routing via the Laravel instance? My immediate suspicion is Guzzle is the culprit behind no cookies coming through with the requests. Cookie::queue() is a Laravel specific feature so I wouldn't think Guzzle would know anything about them.
Replace Guzzle in one of the routes where the issue occurs. Start with a new Request instance and make the internal api call like:
// create new Illuminate request
$request = Request::create('/api/users', $action, $data, [], [], [
'Accept' => 'application/json',
]);
// let the application instance handle the request
$response = app()->handle($request);
// return the Illuminate response with cookies
return $response->withCookies($myCookies);
I do something similar to this in a couple applications and never had any problems with cookies or accessing server variables. Granted, it's only for authentication, the rest of the api calls are through axios.

Single sign on using SimpleSamlPhp wrapper on Laravel

Implementing single sign on in my laravel application. I have decided to use this plugin https://github.com/aacotroneo/laravel-saml2 which is basically a wrapper on famous SimpleSamlPhp.
I downloaded the code via composer and as per given information Remember that you don't need to implement those routes, but you'll need to add them to your IDP configuration. For example, if you use simplesamlphp, add the following to /metadata/sp-remote.php
$metadata['http://laravel_url/saml/metadata'] = array(
'AssertionConsumerService' => 'http://laravel_url/saml/acs',
'SingleLogoutService' => 'http://laravel_url/saml/sls',
//the following two affect what the $Saml2user->getUserId() will return
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
'simplesaml.nameidattribute' => 'uid'
);
I can't find metadata/sp-remote.php, any idea? and as far as http://laravel_url/saml/acs is concerned, do I need to deploy saml on the server? because at the moment the plugin code is in vendors in laravel core architecture code hierarchy.
First some background:
There are two parts to any SAML interaction - the Identity Provider ("IDP") and the Service Provider ("SP"). The IDP is the master authenticator if you like, to which various applications (SPs) connect.
The idea is that the user visits your app, which in turn communicates as a Service Provider to the Identity Provider to get your credentials. And because multiple apps / SPs connect to the same IDP, you get the benefits of a single sign-on.
During the set-up phase, metadata configurations are swapped between the SPs and IDP to establish trust between them. This isn't user-level data -- it's application-level data that allows them to talk.
OK. So now on to your question:
The package you are using allows your Laravel app to talk to an IDP, but before it can do so you need to swap some metadata. The metadata for your app is the snippet above. This needs to go in the IDP configurations, which is where you will find this metadata/sp-remote (or more precisely metadata/saml20-sp-remote, which is where you paste this in.
If you haven't done so already, I'd recommend using [https://simplesamlphp.org/docs/stable/][1] as the IDP here as the Laravel package works with it pretty much out of the box.
One final tip: if you are using SAML2, then I found that you need to change the metadata key to refer to saml2 instead of saml above. ie $metadata['http://laravel_url/saml2/metadata'] and not $metadata['http://laravel_url/saml/metadata']
I hope this will help others. I added saml2_settings.php in the config folder.
Updated the routes:
'logoutRoute' => '/logout',
'loginRoute' => '/homepage',
'errorRoute' => '/error',
updated x509cert (publickey.cer) and privateKey
Updated 'entityId', added the url of metadata xml.
Updated singleLogoutService and rest of the required details in the saml2_settings.php file.
Added two listeners
1) for login event
2) for logout event
Updated the routes file like this:
\Illuminate\Support\Facades\Event::listen('Aacotroneo\Saml2\Events\Saml2LogoutEvent', function ($event) {
\Illuminate\Support\Facades\Auth::logout();
\Illuminate\Support\Facades\Session::save();
return redirect("login");
});
\Illuminate\Support\Facades\Event::listen('Aacotroneo\Saml2\Events\Saml2LoginEvent', function (\Aacotroneo\Saml2\Events\Saml2LoginEvent $event) {
$user = $event->getSaml2User();
$userData = [
'id' => $user->getUserId(),
'attributes' => $user->getAttributes(),
'assertion' => $user->getRawSamlAssertion()
];
// add the login for auto login based on your settings
/// REDIRECT the user to homepage
}
});

Request data from Laravel API into wordpress

I am working on a project on laravel 5.1, and i want to make it as a RESTFUL api so later we can use the same code and request data from mobile apps or other websites. The project is in its initial stages and i want to make it correct right from the beginning.
Suppose i have a simple route which is calling a the dashboard method on the AdminController. So after logging in it redirects the admin to the dashboard page with some data.
/******************** Laravel Project ***********************/
//Routes.php
Route::group(['middleware' => 'auth'], function () {
Route::get('dashboard', 'AdminController#dashboard');
});
// AdminController
public function index(){
$data = 'Some Data';
return view( 'superadmin.dashboard')->with('data', $data );
}
Now i want to get the same data in a wordpress project. How will i use this api to just fetch the data variable (without the view) ? I dont want to create another method for that, is there any way i can use the same function to fetch data as a json?
I read in another forum that we can access all the data as a REST like this. But this is not working.
http://admin:admin123#example.dev/dashboard
As always appreciate your help :)
Personally, I would create an application that is the API. In your case this is your Laravel application.
Then I'd make HTTP requests to the API from Wordpress, or a mobile application.
I find returning JSON from the API is easier to work with. Laravel makes this easy:
return Response::json(array(
'username' => 'superadmin',
'role' => 'admin',
'friends' => array(
'2345',
'884'
)
));
Also, don't send your username and password like that. HTTP auth is insecure. http://adrianotto.com/2013/02/why-http-basic-auth-is-bad/
I tend to use OAuth to secure my APIs.

Best practice of writing custom authentication mechanism on Yii2

I need to write a very specific authentication for my web application. There is API on the side which accepts login + password pair and returns the result (and, a token). I don't want to store any login information on the Yii2 side besides a login token i've got from API. And this must be the only way i auth my clients (so i don't use OAuth-like application).
What is the best practive to override "classic" code in Yii2? Just use filters and modify User model?
Example:
First, i recieve a token and save it somewhere for a session:
$token = GatewayAPI::login($user, $password);
Then, every internal request i do will look like this:
$result = GatewayAPI::addPosition($token, $data);
So, i don't have any database to work with, just cache and memory. Almost everything is handled on API side.
My task is to implement login check - if token is recieved from API - then it's considered as a success. And to store that token for use within current session (probably in memcache, it must not be opened to public).
As a matter of fact Yii2 does not require login/password anywhere.
You don't need to modify or extend User model if you mean \yii\web\User.
You need to create your own class implementing IdentityInterface and set this class as userIdentity in your config components->user->identityClass:
[
'components' => [
'user' => [
'class' => 'yii\web\User', // not necessary, this is by default
'identityClass' => 'my\namespace\User'
]
]
]
There are 5 methods in the interface and they are not about login/pass. This class of yours may store in your db everything you want.
For example you may copy any of popular user modules to your project, remove everything related to storing and searching by login/pass from that User model and add your API functionality - and it will work.
UPD.
Your added functionality will look like this:
$token = GatewayAPI::login($user, $password);
$user = \my\namespace\User::findOne(['token' => $token]);
Yii::$app->user->login($user);

Categories