i use the latest v2 paypal php sdk sandbox and samples with laravel framework, the create order always success but when capture the order it always fails
and return this error:
"{"name":"UNPROCESSABLE_ENTITY",
"details":[
{"issue":"COMPLIANCE_VIOLATION",
"description":"Transaction cannot be processed due to a possible compliance violation. To get more information about the transaction, call Customer Support."}],
"message":"The requested action could not be performed, semantically incorrect, or failed business validation.",
"debug_id":"d701744348160",
"links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-COMPLIANCE_VIOLATION","rel":"information_link","method":"GET"}]}
my web.php file :
Route::get('capture_order', 'PayController#capture_order')->name('capture_order');
Route::get('create_order', 'PayController#create_order')->name('create_order');
Route::get('cancel', 'PayController#cancel')->name('payment.cancel');
Route::get('return', 'PayController#return')->name('payment.return');
Route::get('success', 'PayController#success')->name('payment.success');
& the PayController :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
class PayController extends Controller
{
public $clientId;
public $clientSecret;
public $client;
public $cancel_url = 'http://localhost:8000/cancel';
public $return_url = 'http://localhost:8000/return';
public function __construct()
{
$mode = config('paypal.mode', 'sandbox');
if ($mode == "live") {
$this->clientId = config('paypal.live.client_id');
$this->clientSecret = config('paypal.live.client_secret');
} else {
$this->clientId = config('paypal.sandbox.client_id');
$this->clientSecret = config('paypal.sandbox.client_secret');
}
$environment = new SandboxEnvironment($this->clientId, $this->clientSecret);
$this->client = new PayPalHttpClient($environment);
}
private function buildRequestBody()
{
return [
'intent' => 'CAPTURE',
'application_context' =>[ "cancel_url" => $this->cancel_url,
"return_url" => $this->return_url],
'purchase_units' =>
[
0 => [
'amount' =>
[
'currency_code' => 'USD',
'value' => '20'
]
]
]
];
}
public function create_order()
{
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = $this->buildRequestBody();
try {
$response = $this->client->execute($request);
foreach ($response->result->links as $key => $value) {
if ($value->rel == "approve")
{
return redirect($value->href);
}
}
}catch (\Exception $ex) {
echo $ex->statusCode;
print_r($ex->getMessage());
}
}
public function capture_order(Request $request)
{
// if ($request->token) {
$request = new OrdersCaptureRequest($request->token);
$request->prefer('return=representation');
try {
$response = $this->client->execute($request);
}catch (\Exception $ex) {
echo $ex->statusCode;
dd($ex->getMessage());
}
// }
}
/**
* Responds with a welcome message with instructions
*
* #return \Illuminate\Http\Response
*/
public function cancel(Request $request)
{
dump($request->all());
dd('Your payment is canceled. You can create cancel page here.');
}
/**
* Responds with a welcome message with instructions
*
* #return \Illuminate\Http\Response
*/
public function return(Request $request)
{
if ($request->token) {
return redirect()->route('capture_order', [
'token' => $request->token,
'PayerID' => $request->PayerID
]);
}
dd($request->all());
}
}
i use paypal php sdk with a sandbox account.
can i use the old paypal version or it's completely deprecated ?
waiting your help :)
COMPLIANCE_VIOLATION
This problem is most likely related to the country of the receiving sandbox Business account. Create a new account for a different country such as US, then create a new REST app that uses that sandbox account, and test its sandbox clientid/secret in sandbox mode instead.
For later use in live mode, ensure that if the live business account is from one of the countries that require it, that the live account has a valid auto sweep withdrawal method active and enabled on the account, such as a US bank or local visa card. If you need help configuring auto sweep for live mode, contact PayPal's business support
i call the support and the response was:
Funds received into Egyptian accounts need to be automatically withdrawn to an attached funding source, such as a bank. You can set this up by going into the account settings section of the account, then the "money, banks and cards" section and at the bottom of that page you'll find "automatic withdrawal" where you can specify a financial instrument to use for automatic withdrawals -- https://www.sandbox.paypal.com/businessmanage/account/money
thanks for u all :)
Related
I recently changed my DocuSign integration to use the JWT OAuth flow. To achieve this I have a few classes.
OAuth Client
<?php
namespace App\DocuSign;
use DocuSign\eSign\Client\ApiClient;
use DocuSign\eSign\Client\Auth\OAuth;
use DocuSign\eSign\Configuration;
use Exception;
use Illuminate\Support\Facades\Log;
/**
* Helper class to generate a DocuSign Client instance using JWT OAuth2.
*
* #see
*
*/
class OAuthClient
{
/**
* Create a new DocuSign API Client instance using JWT based OAuth2.
*/
public static function createApiClient()
{
$config = (new Configuration())->setHost(config('docusign.host'));
$oAuth = (new OAuth())->setOAuthBasePath(config('docusign.oauth_base_path'));
$apiClient = new ApiClient($config, $oAuth);
try {
$response = $apiClient->requestJWTUserToken(
config('docusign.integrator_key'),
config('docusign.user_id'),
config('docusign.private_key'),
'signature impersonation',
60
);
if ($response) {
$accessToken = $response[0]['access_token'];
$config->addDefaultHeader('Authorization', 'Bearer ' . $accessToken);
$apiClient = new ApiClient($config);
return $apiClient;
}
} catch (Exception $e) {
// If consent is required we just need to give the consent URL.
if (strpos($e->getMessage(), 'consent_required') !== false) {
$authorizationUrl = config('docusign.oauth_base_path') . '/oauth/auth?' . http_build_query([
'scope' => 'signature impersonation',
'redirect_uri' => config('docusign.redirect_url'),
'client_id' => config('docusign.integrator_key'),
'response_type' => 'code'
]);
Log::critical('Consent not given for DocuSign API', [
'authorization_url' => $authorizationUrl
]);
abort(500, 'Consent has not been given to use the DocuSign API');
}
throw $e;
}
}
}
Signature Client Service
<?php
namespace App\DocuSign;
use DocuSign\eSign\Api\EnvelopesApi;
use DocuSign\eSign\Client\ApiClient;
class SignatureClientService
{
/**
* DocuSign API Client
*/
public ApiClient $apiClient;
/**
* Create a new instance of our class.
*/
public function __construct()
{
$this->apiClient = OAuthClient::createApiClient();
}
/**
* Getter for the EnvelopesApi
*/
public function getEnvelopeApi(): EnvelopesApi
{
return new EnvelopesApi($this->apiClient);
}
}
Then, in my constructors where I want to use it I'm doing
/**
* Create a new controller instance
*/
public function __construct()
{
$this->clientService = new SignatureClientService();
$this->envelopesApi = $this->clientService->getEnvelopeApi();
}
Finally, I use it like so
$envelopeSummary = $this->envelopesApi->createEnvelope(config('docusign.api_account_id'), $envelopeDefinition);
But I get an error that reads
DocuSign\eSign\Client\ApiException: Error while requesting server,
received a non successful HTTP code [400] with response Body:
O:8:"stdClass":2:{s:9:"errorCode";s:21:"USER_LACKS_MEMBERSHIP";s:7:"message";s:60:"The
UserID does not have a valid membership in this Account.";} in
/homepages/45/d641872465/htdocs/sites/ita-portal/vendor/docusign/esign-client/src/Client/ApiClient.php:344
I researched this and this would imply that the user is not within the account, but they are. I also checked that this account owns the envelopes that I'm trying to send.
For reference I took inspiration for envelope sending from here: https://developers.docusign.com/docs/esign-rest-api/how-to/request-signature-template-remote/
What I think is happening is that the request is going to the wrong server or the wrong account.
I'd suggest using a packet analyser like Fiddler or Wireshark to log where your requests are headed (or just log the request within your application)
The auth URLs seem to be correct since you're not getting a 401 unauthorised error but the envelopes and other queries' must match the base URL located in your account under the Apps and Keys page. It would be of the form demo.docusign.net for our demo environment or xxx.docusign.net for our production environment
I am using oauth2-microsoft to develop a 'sign in with Microsoft' tool for my app. I'm successfully authenticating and receiving a token, but then I receive an error from the sample code.
I am using the sample code below and have tried various combinations of URLs in the 'urlResourceOwnerDetails' field, including leaving it blank.
$provider = new \Stevenmaguire\OAuth2\Client\Provider\Microsoft([
'clientId' => '<redacted>',
'clientSecret' => '<redacted>',
'redirectUri' => 'http://localhost/test.php',
'urlAuthorize' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'urlAccessToken' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
'urlResourceOwnerDetails' => 'https://graph.microsoft.com/v1.0/me/drive'
]);
$options = [
'scope' => ['wl.basic', 'wl.signin']
];
After this comes authentication and token generation.
Then this line throws errors:
$user = $provider->getResourceOwner($token);
A token is definitely being generated, as I can echo $token and see it.
The above code should create a $user object that contains details about the logged in user. However, instead it generates these errors:
If 'urlResourceOwnerDetails' is set to https://graph.microsoft.com/v1.0/me/drive I get:
League\OAuth2\Client\Provider\Exception\IdentityProviderException: Access token is empty
If 'urlResourceOwnerDetails' is set to https://outlook.office.com/api/v2.0/me I get:
UnexpectedValueException: Invalid response received from Authorization Server. Expected JSON.
And if 'urlResourceOwnerDetails' is empty I get:
GuzzleHttp\Exception\RequestException: cURL error 3: malformed (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
Any ideas, please?
It appears oauth2-microsoft does not support Microsoft Graph Auth to a full extent at the moment, refer for example this thread
Regarding the error
League\OAuth2\Client\Provider\Exception\IdentityProviderException:
Access token is empty
access token is expected to be passed as Authorization header but according to Microsoft.php provider implementation it is passed instead as query string:
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
$uri = new Uri($this->urlResourceOwnerDetails);
return (string) Uri::withQueryValue($uri, 'access_token', (string) $token);
}
The way how library is designed, the following provider class could be introduced to support Microsoft Graph calls (by including access token in the Authorization header of a request)
class MicrosoftGraphProvider extends AbstractProvider
{
/**
* Get provider url to fetch user details
*
* #param AccessToken $token
*
* #return string
*/
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return 'https://graph.microsoft.com/v1.0/me';
}
protected function getAuthorizationHeaders($token = null)
{
return ['Authorization'=>'Bearer ' . $token->getToken()];
}
public function getBaseAuthorizationUrl()
{
return 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
}
public function getBaseAccessTokenUrl(array $params)
{
return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
}
protected function getDefaultScopes()
{
return ['openid profile'];
}
protected function checkResponse(\Psr\Http\Message\ResponseInterface $response, $data)
{
// TODO: Implement checkResponse() method.
}
protected function createResourceOwner(array $response, AccessToken $token)
{
return (object)$response;
}
}
I'm new to Twilio. I'm using Twilio for phone verification of my app. I'm using Laravel 5.5 for the backend & APIs. I've successfully sent the SMS to phone. I'm getting the call from Twilio but it says an application error. It doesn't read what I want to hear.
Below I'm giving every detail of my code.
Used composer require twilio/sdk for Twilio.
This is my Controller.
use Twilio\Rest\Client;
use Twilio\Twiml;
class AppUserController extends Controller{
private $account_sid;
private $auth_token;
private $twilio_number;
public function __construct(){
$this->account_sid = Config::get('envvalue.account_sid');
$this->auth_token = Config::get('envvalue.auth_token');
$this->twilio_number = Config::get('envvalue.twilio_number');
}
public function reVerification(Request $request){
$client = new Client($this->account_sid, $this->auth_token);
try {
$client->account->calls->create(
$receiverNumber,
$this->twilio_number,
array(
"url" => "http://demo.bitcanny.com/marine-admin/public/api/twiml/"
)
);
return response()->json([
'success' => true,
'statusCode' => '200',
'message' => 'Otp send again'
], 200);
}
catch (Exception $e) {
return $e->getMessage();
}
}
public function twiml(){
// A message for Twilio's TTS engine to repeat
$sayMessage = 'Hello.';
$twiml = new Twiml();
$twiml->say($sayMessage);
$response = Response::make($twiml, 200);
$response->header('Content-Type', 'text/xml');
return $response;
}
}
I found the solution. There's a silly mistake. I didn't use Response in the header of my controller.
use Response;
I am trying to configure guard with an OAuth 2 connection.
I am trying to do this with a redirection in the getCredentials function to the Microsoft login website but I can't make it work. I don't know how I can make it worked.
It seems there is no redirection possible in this function.
public function getCredentials(Request $request)
{
$provider = new Microsoft([
'clientId' => '0000000032624',
'clientSecret' => 'my-secret',
'redirectUri' => 'https://mysite/oauthlogin'
]);
if(!$request->query->has('code')){
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$request->getSession()->set('oauth2state', $provider->getState());
//This doesn't work
return new RedirectResponse($authUrl);
// Check given state against previously stored one to mitigate CSRF attack
}elseif ( empty($request->query->get('state')) || ($request->query->get('state')!==$request->getSession()->get('oauth2state')) ){
return null;
}else{
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $request->query->get('code')
]);
try {
//when log with microsoft, check if user is allowed
// We got an access token, let's now get the user's details
$user = $provider->getResourceOwner($token);
} catch (Exception $e) {
// Failed to get user details
}
}
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($user->getEmail());
}
public function checkCredentials($credentials, UserInterface $user)
{
// check credentials - e.g. make sure the password is valid
// no credential check is needed in this case
// return true to cause authentication success
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$url = $this->router->generate('homepage');
return new RedirectResponse($url);
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$data = array(
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
// or to translate this message
// $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
);
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $data);
$url = $this->router->generate('login');
return new RedirectResponse($url);
}
Function getCredentials() is not supposed to return a Response, it provide the credentials used in getUser().
In the getUser() documentation :
The credentials are the return value from getCredentials()
You may throw an AuthenticationException if you wish. If you return
null, then a UsernameNotFoundException is thrown for you.
In case of exception thrown, onAuthenticationFailure() is called and here you can return your RedirectResponse.
For more detailled informations, see the source code of the \Symfony\Component\Security\Guard\GuardAuthenticatorInterface which contains a lots of explanations in its methods.
When I try to access phpmailer/get_outh_token.php to get refresh token server returns:
HTTP ERROR 500
Client ID, Secret key and redirect Uri are correct, and i am using it already in Wordpress.
I have downloaded last version of phpmailer, also tested with old version with same result.
I found what cause this, it is this part:
namespace League\OAuth2\Client\Provider;
When I remove it, then script loads with errors of course because
Provider namespace is not loaded.
Website working on PHP 7.
This is full code of get_outh_token.php, and it is original (just credentials are different of course):
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
/**
* Get an OAuth2 token from Google.
* * Install this script on your server so that it's accessible
* as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
* e.g.: http://localhost/phpmail/get_oauth_token.php
* * Ensure dependencies are installed with 'composer install'
* * Set up an app in your Google developer console
* * Set the script address as the app's redirect URL
* If no refresh token is obtained when running this file, revoke access to your app
* using link: https://accounts.google.com/b/0/IssuedAuthSubTokens and run the script again.
* This script requires PHP 5.4 or later
* PHP Version 5.4
*/
namespace League\OAuth2\Client\Provider; //when i remove this line, than page load without 500, but with errors.
require 'vendor/autoload.php';
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use Psr\Http\Message\ResponseInterface;
session_start();
//If this automatic URL doesn't work, set it yourself manually
$redirectUri = 'https://www.secret.co/phpmailer/get_oauth_token.php';
//These details obtained are by setting up app in Google developer console.
$clientId = 'secret.apps.googleusercontent.com';
$clientSecret = 'secret';
class Google extends AbstractProvider
{
use BearerAuthorizationTrait;
const ACCESS_TOKEN_RESOURCE_OWNER_ID = 'id';
/**
* #var string If set, this will be sent to google as the "access_type" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2WebServer#offline
*/
protected $accessType;
/**
* #var string If set, this will be sent to google as the "hd" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2Login#hd-param
*/
protected $hostedDomain;
/**
* #var string If set, this will be sent to google as the "scope" parameter.
* #link https://developers.google.com/gmail/api/auth/scopes
*/
protected $scope;
public function getBaseAuthorizationUrl()
{
return 'https://accounts.google.com/o/oauth2/auth';
}
public function getBaseAccessTokenUrl(array $params)
{
return 'https://accounts.google.com/o/oauth2/token';
}
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return ' ';
}
protected function getAuthorizationParameters(array $options)
{
if (is_array($this->scope)) {
$separator = $this->getScopeSeparator();
$this->scope = implode($separator, $this->scope);
}
$params = array_merge(
parent::getAuthorizationParameters($options),
array_filter([
'hd' => $this->hostedDomain,
'access_type' => $this->accessType,
'scope' => $this->scope,
// if the user is logged in with more than one account ask which one to use for the login!
'authuser' => '-1'
])
);
return $params;
}
protected function getDefaultScopes()
{
return [
'email',
'openid',
'profile',
];
}
protected function getScopeSeparator()
{
return ' ';
}
protected function checkResponse(ResponseInterface $response, $data)
{
if (!empty($data['error'])) {
$code = 0;
$error = $data['error'];
if (is_array($error)) {
$code = $error['code'];
$error = $error['message'];
}
throw new IdentityProviderException($error, $code, $data);
}
}
protected function createResourceOwner(array $response, AccessToken $token)
{
return new GoogleUser($response);
}
}
//Set Redirect URI in Developer Console as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
$provider = new Google(
array(
'clientId' => $clientId,
'clientSecret' => $clientSecret,
'redirectUri' => $redirectUri,
'scope' => array('https://mail.google.com/'),
'accessType' => 'offline'
)
);
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: ' . $authUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken(
'authorization_code',
array(
'code' => $_GET['code']
)
);
// Use this to get a new access token if the old one expires
echo 'Refresh Token: ' . $token->getRefreshToken();
}
I know this question is old, but I was having same issue.
All I did was to install league/oauth2-google via composer
composer require league/oauth2-google
This helped me figure it out
Hope it help some else.