How can I send cookie while using REST API? - php

Using Laravel 5 and trying to send some data from my site to another one, which provides me with the REST API. But they use cookies as a authorization. For this moment, I've passed auth successfully. And stuck on how should I send this cookie to API interface via POST method? Here is my listing.
Thanx in advance.
P.S. All things are going on inside the controller.
if (Cookie::get('amoauth') !== null) {
//COOKIE IS HERE
$client = new Client();
$newlead = $client->post('https://domain.amocrm.ru/private/api/v2/json/leads/set', [
'add' => [
'add/name' => 'TEST LEAD',
'add/date_create' => time(),
'add/last_modified' => time(),
'add/status_id' => '1',
'add/price' => 5000
]
]);
} else {
$client = new Client();
$auth = $client->post('https://domain.amocrm.ru/private/api/auth.php',[
'USER_LOGIN' => 'login',
'USER_HASH' => 'hash',
'type' => 'json'
]);
$auth = $auth->getHeaders('Set-Cookie');
Cookie::queue('amoauth', $auth, 15);
return redirect('/test');
}
Now it returns me the following:
Client error: `POST https://domain.amocrm.ru/private/api/v2/json/leads/set` resulted in a `401 Unauthorized` response.

Found the solution: switched to ixudra/curl.

Related

Get API response URL param using Guzzle HTTP request in Guzzle 7

I searched online but couldn't find a proper solution. I am calling a Spring service with a POST request using Guzzle Client, The service in case of any errors provides the error message in its URL param like: http://localhost:8085/fedauth/null?errMessage=Mot%20de%20passe%20invalide%20pour%20l'utilisateur%20Karan%20Sharma.. How can I fetch this param errMessage using Guzzle. Below is my code with Slim in PHP.
$data = [
'userName' => base64_encode($userName),
'userPassword' => base64_encode($userPassword),
'institution' => $institution,
'redirectUrl' => $redirectUrl,
'callerUrl' => $callerUrl,
'clientId' => $clientId,
'encryptMode' => $encryptMode,
'moodleLandPage' => $moodleLandPage,
'login' => $login,
'isEncrypted' => true
];
try {
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
} catch (Exception $exception) {
return $response->write(json_encode(['error' => $exception->getMessage(), "auth" => "0" ]));
}
I have tried using the getEffectiveUrl() method but its no longer supported in Guzzle 7
I guess you get the response as a redirect url? Your question is not clear in that point. In this case you can access it like this:
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getEffectiveUrl();
like here: https://docs.guzzlephp.org/en/5.3/http-messages.html#responses
Actually found the answer. You need to add track redirects option as true and then use $response->getHeaderLine('X-Guzzle-Redirect-History'); like below
$client = new GuzzleHttp\Client(['headers' => [ 'Content-Type' => 'application/x-www-form-urlencoded'], 'verify' => false, 'allow_redirects' => ['track_redirects' => true]]);
$apiResponse = $client->post( $_ENV['FEDAUTH_API_URL'], ['form_params'=> $data]);
echo $apiResponse->getHeaderLine('X-Guzzle-Redirect-History');

How to make a request with PHPLeague oAuth2 client?

I'm integrating with a affiliate platform for a client which provides an oAuth2 API, don't usually do massive amounts of work with oAuth2.
I've decided for my client, I'll use the PHP Leagues oAuth2 package: https://github.com/thephpleague/oauth2-client
Anyway, I've got an accessToken no problem! using the following:
$provider = new GenericProvider([
'clientId' => $this->config->affiliates->rakuten->clientId,
'clientSecret' => $this->config->affiliates->rakuten->clientSecret,
'redirectUri' => 'http://www.newintoday.com/',
'urlAuthorize' => 'https://api.rakutenmarketing.com/token', // Ignore
'urlAccessToken' => 'https://api.rakutenmarketing.com/token',
'urlResourceOwnerDetails' => 'https://api.rakutenmarketing.com/' // Ignore
]);
try {
// Try to get an access token using the resource owner password credentials grant.
$accessToken = $provider->getAccessToken('password', [
'username' => $this->config->affiliates->rakuten->username,
'password' => $this->config->affiliates->rakuten->password,
'scope' => $this->config->affiliates->rakuten->publisherId,
]);
$productSearchApiBaseUri = 'https://api.rakutenmarketing.com/productsearch/1.0';
$request = $provider->getAuthenticatedRequest('GET', $productSearchApiBaseUri, $accessToken, [
'body' => '?keyword=shirt',
]);
\Utils::dump($provider->getResponse($request));
} catch (IdentityProviderException $e) {
echo $e->getMessage();
}
My question is once we have the accessToken what do we use in it to make the request, I followed through the code and came up with the above but the API responds saying that the keyword is not specified? Is
$request = $provider->getAuthenticatedRequest('GET', $productSearchApiBaseUri, $accessToken, [
'body' => 'keyword=shirt',
]);
The correct way to provide it with a GET variable?
Thanks in advance.
Realised I could simply include the get vars in the URI alla:
$productSearchApiBaseUri = 'https://api.rakutenmarketing.com/productsearch/1.0?keyword=shirt';

How to use oAuth with Guzzle 5 (or, better, with Guzzle 6)

I'm trying to connect to the WooCommerce API using Guzzle 5 (Guzzle 6 seems not has oAuth options o.O). Woocommerce requires the oAuth authentication method to work.
This is the code I'm using:
<?php
/**
* Example of usage of Guzzle 5 to get information
* from a WooCommerce Store.
*/
require('../vendor/autoload.php');
use GuzzleHttp\Client;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
use GuzzleHttp\Exception\RequestException;
$consumer_key = 'my_consumer_key'; // Add your own Consumer Key here
$consumer_secret = 'my_consumer_secret'; // Add your own Consumer Secret here
$store_url = 'http://example.com'; // Add the home URL to the store you want to connect to here
$api_path = '/wc-api/v2/';
$api_end_point = [
'root' => '',
'orders' => 'orders'
];
$base_uri = $store_url . $api_path;
$client = new Client([
'base_url' => $base_uri,
'defaults' => ['auth' => 'oauth']
]);
$oauth = new Oauth1([
'consumer_key' => $consumer_key,
'consumer_secret' => $consumer_secret,
'request_method' => 'query'
]);
$client->getEmitter()->attach($oauth);
try
{
$res = $client->get($api_end_point['orders']);
}
catch (RequestException $e)
{
$res = $e;
if ($e->hasResponse())
{
$res = $e->getResponse();
}
}
print_r($res);
echo $res->getStatusCode();
// "200"
echo $res->getHeader('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// {"type":"User"...'
This code returns a
woocommerce_api_authentication_error: Invalid Signature - provided
signature does not match
Using pure curl functions (using this package in which I've put some functions I found here), instead, it works and I get all orders and other data I want.
SOME OTHER DETAILS
To use Guzzle 5 and oAuth I use the those composer packages:
"require": {
"guzzlehttp/guzzle": "~5.0"
},
"require-dev": {
"guzzlehttp/oauth-subscriber": "~0.2",
},
It seems there are some things that are different in creating the signature: the one created by the library I've used until now works, but the one created by the oAuth plugin (using the method getSignature()) for Guzzle doesn't and I'm not so used to use oAuth to find the error. Is there someone who can help me identify the problem?
Updating #Aerendir answer
In his pull request, #Aerendir wrote:
In my case, I did the editing as I were trying to connect to the
WooCommerce API version 2 but that version of the API didn't implement
correctly the OAuth Core 1.0a spec. In fact, they fixed this issue in
the version 3 of the API. See Differences between V3 and older
versions.
source: https://github.com/guzzle/oauth-subscriber/pull/42#issuecomment-185631670
So, to make his answer work properly, we need to use wc-api/v3/ instead of wc-api/v2/.
The following code, works using Guzzle 6, oauth and WooCommerce api v3:
use GuzzleHttp\Client,
GuzzleHttp\HandlerStack,
GuzzleHttp\Handler\CurlHandler,
GuzzleHttp\Subscriber\Oauth\Oauth1;
$url = 'http://localhost/WooCommerce/';
$api = 'wc-api/v3/';
$endpoint = 'orders';
$consumer_key = 'ck_999ffa6b1be3f38058ed83e5786ac133e8c0bc60';
$consumer_secret = 'cs_8f6c96c56a7281203c2ff35d71e5c4f9b70e9704';
$handler = new CurlHandler();
$stack = HandlerStack::create($handler);
$middleware = new Oauth1([
'consumer_key' => $consumer_key,
'consumer_secret' => $consumer_secret,
'token_secret' => '',
'token' => '',
'request_method' => Oauth1::REQUEST_METHOD_QUERY,
'signature_method' => Oauth1::SIGNATURE_METHOD_HMAC
]);
$stack->push($middleware);
$client = new Client([
'base_uri' => $url . $api,
'handler' => $stack
]);
$response = $client->get( $endpoint, [ 'auth' => 'oauth' ] );
echo $response->getStatusCode() . '<br>';
echo $response->getHeaderLine('content-type') . '<br>';
echo $response->getBody();
Now the plugin OauthSubscriber is available only for Guzzle 6.
Testing around again, I've found the bug: it is in the method signUsingHmacSha1()that anyway adds an umpersand (&) to the string to sign and this causes the error from WooCommerce.
I've opened a issue on GitHub and sent a pull request to fix the bug.
The correct way to connect to the WooCommerce API V2 using Guzzle 6 (once the bug is fixed! Take care of the version of the WooCommerce API you connect: the API v3 still doesn't work!) is this:
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
$options = array(
// Add the home URL to the store you want to connect to here (without the end / )
'remoteUrl' => 'http://example.com/',
// Add your own Consumer Key here
'remoteConsumerKey' => 'ck_4rdyourConsumerKey8ik',
// Add your own Secret Key here
'remoteSecretKey' => 'cs_738youconsumersecret94i',
// Add the endpoint base path
'remoteApiPath' => 'wc-api/v2/',
);
$remoteApiUrl = $options['remoteUrl'] . $options['remoteApiPath'];
$endpoint = 'orders';
$handler = new CurlHandler();
$stack = HandlerStack::create($handler);
$middleware = new Oauth1([
'consumer_key' => $options['remoteConsumerKey'],
'consumer_secret' => $options['remoteSecretKey'],
'token_secret' => '',
'token' => '',
'request_method' => Oauth1::REQUEST_METHOD_QUERY,
'signature_method' => Oauth1::SIGNATURE_METHOD_HMAC
]);
$stack->push($middleware);
$client = new Client([
'base_uri' => $remoteApiUrl,
'handler' => $stack
]);
$res = $client->get($endpoint, ['auth' => 'oauth');
As told, this connection works only with the version 2 of the WooCommerce API.
I'm investigating to understand why the V3 doesn't work.

Setting post data with a Laravel request object

I'm trying to test a Laravel API endpoint and want to call it in code.
$request = Request::create( $path, $method );
$response = Route::dispatch( $request );
This snippet works fine for GET but I need to be able to set up POST calls too. Setting the $method to POST works as well, but I can't find documentation detailing how to attach post data.
Any advice?
As you mentioned in the comments, you could use $this->call() but you can actually do it with your current code too. If you take a look at the signature of the Request::create() function you can see that it takes $parameters as third argument:
public static function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null)
And the docblock says: The query (GET) or request (POST) parameters
So you can simply add the data to Request::create()
$data = array('foo' => 'bar');
$request = Request::create( $path, $method, $data );
$response = Route::dispatch( $request );
I've spent nearly a day trying to get this working myself for social authentication with passport and Angular front-end.
When I use the Restlet API Client to make the request I always get a successful response.
Restlet Client Request
Restlet client response
However using the following method of making internal requests always gave me an error.
$request = Request::create(
'/oauth/token',
'POST',
[
'grant_type' => 'social',
'client_id' => 'your_oauth_client_id',
'client_secret' => 'your_oauth_client_secret',
'provider' => 'social_auth_provider', // e.g facebook, google
'access_token' => 'access_token', // access token issued by specified provider
]
);
$response = Route::dispatch($request);
$content = json_decode($response->getContent(), true);
if (! $response->isSuccessful()) {
return response()->json($content, 401);
}
return response()->json([
'content' => $content,
'access_token' => $content['access_token'],
'refresh_token' => $content['refresh_token'],
'token_type' => $content['token_type'],
'expires_at' => Carbon::parse(
$content['expires_in']
)->toDateTimeString()
]);
This specific error:
{
error: "unsupported_grant_type",
error_description: "The authorization grant type is not supported by the
authorization server.",
hint: "Check that all required parameters have been provided",
message: "The authorization grant type is not supported by the authorization server."
}
I had the feeling it has to do with the way the form data is sent in the request, so while searching for a proper way to make such internal requests in laravel I came across this sample project with a working implementation: passport-social-grant-example.
In summary here's how to do it:
$proxy = Request::create(
'/oauth/token',
'POST',
[
'grant_type' => 'social',
'client_id' => 'your_oauth_client_id',
'client_secret' => 'your_oauth_client_secret',
'provider' => 'social_auth_provider', // e.g facebook, google
'access_token' => 'access_token', // access token issued by specified provider
]
);
return app()->handle($proxy);
Hope this helps.

How to get past login screen on Guzzle call

I have to send information to an external website using cURL. I set up Guzzle on my Laravel application. I have the basics set up, but according to the documentation of the website, there is an action that's required for the username and password. How can I pass the 'action' along with the credentials needed to log in and get access?
The website states:
curl [-k] –dump-header <header_file> -F “action=login” -F “username=<username>” -F “password=<password>” https://<website_URL>
My controller:
$client = new \GuzzleHttp\Client();
$response = $client->get('http://website.com/page/login/', array(
'auth' => array('username', 'password')
));
$xml = $response;
echo $xml;
The website will load on the echo, but it will only pull up the login screen. I need those credentials to bypass the login screen (with a successful login) to get to the portion of information I need for cURL.
curl -F submits a POST request instead of a GET request. So you'll need to modify your code accordingly, something like
$client = new \GuzzleHttp\Client();
$response = $client->post('http://website.com/page/login/', [
'body' => [
'username' => $username,
'password' => $password,
'action' => 'login'
],
'cookies' => true
]
);
$xml = $response;
echo $xml;
See http://guzzle.readthedocs.org/en/latest/quickstart.html#post-requests, http://curl.haxx.se/docs/manpage.html#-F
Edit:
Just add ['cookies' => true] to requests in order to use the auth cookie associated with this GuzzleHttp\Client(). http://guzzle.readthedocs.org/en/latest/clients.html#cookies
$response2 = $client->get('http://website.com/otherpage/', ['cookies' => true]);
I was having trouble getting #JeremiahWinsley's answer to work on newer version of Guzzle so I've updated their code to work as of Guzzle 5.x.
Three major changes are required
Using form_params instead of body to prevent the error "Passing in the "body" request option as an array to send a POST request has been deprecated."
Changing the cookies to use the CookieJar object
Use ->getBody()->getContents() to get the body of the request
Here is the updated code:
$client = new \GuzzleHttp\Client();
$cookieJar = new \GuzzleHttp\Cookie\CookieJar();
$response = $client->post('http://website.com/page/login/', [
'form_params' => [
'username' => $username,
'password' => $password,
'action' => 'login'
],
'cookies' => $cookieJar
]
);
$xml = $response->getBody()->getContents();
echo $xml;
And to continue using cookies in future requests, pass in the cookieJar to the request:
$response2 = $client->get('http://website.com/otherpage/', ['cookies' => $cookieJar]);
I was having trouble getting #JeremiahWinsley's and #Samsquanch's answer to work on newer version of Guzzle. So I've updated the code to work as of Guzzle 6.x.
Guzzle 6.x. documents: http://docs.guzzlephp.org/en/stable/index.html
Here is the updated code:
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
try {
$client = new Client();
$cookieJar = new CookieJar();
$response = $client->request('POST', 'http://website.com/page/login/', [
'form_params' => [
'username' => 'test#example.com',
'password' => '123456'
],
'cookies' => $cookieJar
]);
$response2 = $client->request('GET', 'http://website.com/otherpage/', [
'cookies' => $cookieJar
]);
if ($response2->getStatusCode() == 200) {
return $response2->getBody()->getContents();
} else {
return "Oops!";
}
} catch (\Exception $exception) {
return 'Caught exception: ', $exception->getMessage();
}

Categories