How do I do HTTP basic authentication using Guzzle? - php

I want to do basic access authentication using Guzzle and I am very new to programming. I have no clue what to do. I tried to do this using curl but my environment requires using guzzle.

If you're using Guzzle 5.0 or newer, the docs say that basic auth is specified using the auth parameter:
$client = new GuzzleHttp\Client();
$response = $client->get('http://www.server.com/endpoint', [
'auth' => [
'username',
'password'
]
]);
Please note that the syntax is different if you're using Guzzle 3.0 or earlier. The constructor is different, and you also need to explicitly use the send method on a request to get a response:
$client = new Guzzle\Http\Client();
$request = $client->get('http://www.server.com/endpoint');
$request->setAuth('username', 'password');
$response = $request->send();
A brief addendum
In response to #Matthwew-Knill, yes, you can set a default authorization and implicitly have Guzzle send it in each further request. #Nick's answer is on point. The client constructor takes every parameter you could think of and then some.
Another approach, if you want to get creative, would be to instantiate the client passing it default headers to send on every further request. Simple auth is, after all, an Authorization header. It's computed as:
$client = new Client([
'headers'=>[
'Authorization'=> Basic base64_encode(<username>:<password>)
]
]);
Last but not least please note that filling a simple auth dialog happens only once (upon the virst visit of a given session). This is usually achieved by setting a cookie on the visitor's browser. That cookie in turn contains enough info for the server to identify its matching active session.
Usually, Guzzle requests are stateless, but you can configure Guzzle with a middleware chain to either modify request or responses, for debug purposes and, for this use case, to remember cookies, thus becoming partially stateful.
Please check the detailed procedure in Guzzle Docs. The important thing is that, by instantiating the client with a cookiejar middleware, therefore having the client include it from then on, the first request will remember the server's set-cookie header, and will send it as every further cookie header, making the server recognize the client as a logged in user. Of course, you could also inspect the first response's headers yourself and send its value from then on.
There might be other ways, but I can't think of another right now.

In additional to #amenadiel answer. Sometimes handy specify auth parameters in constructor:
$client = new Client([
'auth' => ['username', 'password'],
]);
Then every request will use this default auth parameters.

This dint work when I used Guzzlev6 and used the advice from #amenadiel. When you use curl, your syntax would look something like
curl -u someone#gmail.com:password http://service.com
behind the scenes it actually takes the "someone#gmail.com:password" bit, base64 encodes it and sends the request with an "Authorization" Header with the encoded value. For this example, that will be:
Authorization: Basic c29tZW9uZUBnbWFpbC5jb206cGFzc3dvcmQ=
Advice from #amenadiel appended an "auth: username,password" header and hence, my authentication kept failing. To achieve this successfully, just craft the header when you are instantiating a Guzzle Client request, i.e
$client = new GuzzleHttp\Client();
$credentials = base64_encode('someone#gmail.com:password');
$response = $client->get('http://www.server.com/endpoint', [
'Authorization' => ['Basic '.$credentials]
]);
That would append the header as curl would, and whatever service you are trying to connect to will stop yelling at you,
Cheers.

According to the Guzzle 6 documentation, you can do a request with basic authorization as simple as this:
$client = new Client();
$response = $client->request(
'POST', /*instead of POST, you can use GET, PUT, DELETE, etc*/
$url,
[
'auth' => ['username', 'password'] /*if you don't need to use a password, just leave it null*/
]
);
echo $response->getBody();
NOTE: You don't need to use base64_encode() at all because it already does it before the request.
I've tested and it works :)
See more at: Guzzle 6 Documentation

$response = $client->request( 'GET', 'your_url', [
'auth' => [
'your_username',
'your_password'
],
'headers' => [
'if you want to pass something in the headers'
]
]
);

You can also configure the auth params when instantiating the client instead of adding it to each request:
$this->client = new \GuzzleHttp\Client([
'base_uri' => $this->endpoint,
'headers' => [
'Authorization' => ['Basic '.base64_encode($this->username.':'.$this->password)],
],
]);
Here are the various doc links for Guzzle 6:
Creating a Client
Request Options
Auth Request Options

According to what #bourgeois247 said about base64 encoding, the following worked perfectly for me on Guzzle 6:
$client = new Client();
$credentials = base64_encode('username:password');
$response = $client->post('url',
[
'headers' => [
'Authorization' => 'Basic ' . $credentials,
],
]);

If you use it with symfony, you can also define it in your configuration file (config/packages/eight_points_guzzle.yaml for symfony4 or flex or config.yml for the other version)
In your configuration file :
eight_points_guzzle:
clients:
your_service:
# Write here the host where to do requests
base_url: "yourURL"
options:
timeout: 30
auth:
- yourLogin # login
- yourPassword # password
plugin: ~
Then, in your service, controller, etc....
$client = $this->getContainer()->get('eight_points_guzzle.client.your_service');
$response = $client->get('yourRoute');
See : https://packagist.org/packages/eightpoints/guzzle-bundle

Related

In Laravel, how do I make a guzzle http post request with csrf token

I want to make an http post to a server URL using GuzzleHTTP. My application is built with Laravel and the guzzle request requires a CSRF token. I've tried a few ways to include it but it isn't working. What is the proper way to include the CSRF token in a guzzle request? Here is my code:
use GuzzleHttp\Client;
$client = new Client();
$response = $client->post(url('/import'), [
'headers' => [
'X-CSRF-Token' => csrf_token()
]
]);
If this is remote laravel server, CSRF tokens can't be expected.
If you want to handle your post request, either pass right token or remove CSRF checking from middleware.
You can do it, by including your route to
protected $except
in your /app/Http/Midddleware/VerifyCsrfToken.php file...

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.

Guzzle Laravel - Login using POST request

What I am trying to do is to login to an external API and retrieve a JSON file. For this I am using Guzzle in Laravel.
I have setup a controller to do this:
$client = new Client([
'base_uri' => 'https://www.space-track.org',
'timeout' => 2.0,
]);
I access the JSON file using:
$response = $client->request('GET', '/basicspacedata/query/class/boxscore');
In order to get the JSON file I am required to login to the API. The API tutorial tells me:
Login by sending a HTTP POST request ('identity=your_username&password=your_password') to: https://www.space-track.org/ajaxauth/login
What I am unable to do is login to the API using Guzzle. I tried following a few Guzzle tutorials and using the 'auth' array to which none worked.
Basically, what I am unable to do is to login to the API using Guzzle.
Here is a basic flow that should work
// Initialize the client
$api = new Client([
'base_uri' => 'https://www.space-track.org',
'cookies' => true, // You have to have cookies turned on for this API to work
]);
// Login
$api->post('ajaxauth/login', [
'form_params' => [
'identity' => '<username>', // use your actual username
'password' => '<password>', // use your actual password
],
]);
// Fetch
$response = $api->get('basicspacedata/query/class/boxscore/format/json');
// and decode some data
$boxscore = json_decode($response->getBody()->getContents());
// And logout
$api->get('ajaxauth/logout');
dd($boxscore);
Now if it's not a one off request and you're planing on extensively using this API you can wrap this "ugliness" in your own service class that exposes a meaningful internal API that allows you to write then something along the lines of
$spaceTrack = new App\Services\SpaceTrack\Client();
$boxscore = $spaceTrack->getBoxscore();
dd($boxscore);

Guzzle HTTP request transforms from POST to GET

I have this very weird thing going on when trying to make post to an external API, I try to make a POST request to the URL but Guzzle make a GET request instead (which is a legal action on this API but returns something different).
Here is the code:
$request = $this->client->createRequest('POST', 'sessions', [
'json' => [
'agent_id' => $agentId,
'url' => $url
],
'query' => [
'api_key' => $this->apiKey
]
]);
echo $request->getMethod(); // comes out as POST
$response = $this->client->send($request);
echo $request->getMethod(); // suddenly becomes GET
Same thing happens when I use $this-client->post(…)
I really have no idea what to do next.
I run into the same problem.
the reason is that Guzzle Changes the Request-Method to 'GET' when there is a location Redirect with code 301 or 302.
I found the 'Problem-Code' in the RedirectMiddleware.php.
But when you see the if-condition you can disable this behavior by adding 'allow_redirects'=>['strict'=>true] to your options.
After finding this option, I discovered that the option is listed in the Guzzle Options Documentation
So yust rewrite your createRequest like this:
$request = $this->client->createRequest('POST', 'sessions', [
'json' => [
'agent_id' => $agentId,
'url' => $url
],
'query' => [
'api_key' => $this->apiKey
],
'allow_redirects'=> ['strict'=>true]
]);
And it should stay Method POST after the redirect.
You're probably getting a 3xx status code so that that the Redirect subscriber kicks in (redirect is enabled by default). From the docs:
[...] Pass an associative array containing the ‘max’ key to specify
the maximum number of redirects and optionally provide a ‘strict’ key
value to specify whether or not to use strict RFC compliant redirects
(meaning redirect POST requests with POST requests vs. doing what
most browsers do which is redirect POST requests with GET requests).
//edit Just saw you kinda answered that yourself in the question comments - still leaving this answer online as it provides some context.
Try to change the key 'query' to 'body'.
Please switch query to form_params. In Guzzle 6 it works.

How to use Goutte without cookie

How to use goutte but don't send cookies back to the server?
I want to do that because the server can manage sessionid in the URL.
I end up using guzzle and browserkit directly without using goutte. Guzzle let you chose to manage or not cookies http://guzzle.readthedocs.org/en/latest/quickstart.html#cookies.
This solved this problem amount others.
If really you like goutte, I guess you can also delete cookie between each requests.
The only way I see is to instantiate the GuzzleClient yourself and pass it to the Goutte client.
Like this:
use Goutte\Client as GoutteClient;
use GuzzleHttp\Client as GuzzleClient;
$guzzleClient = new GuzzleClient(array('defaults' => array(
'allow_redirects' => false,
'cookies' => false
));
$client = new GoutteClient();
$client->setClient($guzzleClient);
$client->request('GET', 'http://example.org');

Categories