Access token persistence
Note: OAuth Access tokens should be stored somewhere securely and/or encrypted. If an attacker gains access to your access token, they could have unrestricted access to whatever resources and scopes were allowed!
By default, access tokens are not persisted anywhere. There are some built-in mechanisms for caching / persisting tokens (in kamermansOAuth2Persistence):
NullTokenPersistence
(default) Disables persistenceFileTokenPersitence
Takes the path to a file in which the access token will be saved.DoctrineCacheTokenPersistence
Takes aDoctrineCommonCacheCache
object and optionally a key name (default:guzzle-oauth2-token
) where the access token will be saved.SimpleCacheTokenPersistence
Takes a PSR-16 SimpleCache and optionally a key name (default:guzzle-oauth2-token
) where the access token will be saved. This allows any PSR-16 compatible cache to be used.Laravel5CacheTokenPersistence
Takes anIlluminateContractsCacheRepository
object and optionally a key name (default:guzzle-oauth2-token
) where the access token will be saved.ClosureTokenPersistence
Allows you to define a token persistence provider by providing closures to handle the persistence functions.
If you want to use your own persistence layer, you should write your own class that implements TokenPersistenceInterface or use the ClosureTokenPersistence provider, which is described at the end of this section.
To enable token persistence, you must use the OAuth2Middleware::setTokenPersistence() or OAuth2Subscriber::setTokenPersistence() method, like this:
Allow_redirects
Specifies whether or not the request should follow redirects. Requests will follow redirects by default. Set
allow_redirects to false to disable redirects.
Authorization code example
There is a full example of using the AuthorizationCode grant type with a RefreshToken in the examples/ directory.
Base urls
Notice that the URL provided to the client’s get() method is relative. Relative URLs will always merge into the
base URL of the client. There are a few rules that control how the URLs are merged.
Client credentials signers
When requesting a new access token, we need to send the required credentials to the OAuth 2 server. Adding information to a request is called signing in this library.
There are two client credentials signers included in kamermansOAuth2SignerClientCredentials:
If the OAuth 2 server you are obtaining an access token from does not support the built-in methods, you can either extend one of the built-in signers, or create your own by implementing kamermansOAuth2SignerClientCredentialsSignerInterface, for example:
Closure-based token persistence
There are plenty of cases where you would like to use your own caching layer to store the OAuth2 data, but there is no adapter included that works with your cache provider. The ClosureTokenPersistence provider makes this case easier by allowing you to define closures that handle the OAuth2 persistence data, as shown in the example below.
// We'll store everything in an array, but you can use any provider you want$cache = [];
$cache_key = "foo";
// Returns true if the item exists in cache$exists = function() use (&$cache, $cache_key) {
return array_key_exists($cache_key, $cache);
};
// Sets the given $value array in cache$set = function(array$value) use (&$cache, $cache_key) {
$cache[$cache_key] = $value;
};
// Gets the previously-stored value from cache (or null)$get = function() use (&$cache, $cache_key, $exists) {
return$exists()? $cache[$cache_key]: null;
};
// Deletes the previously-stored value from cache (if exists)$delete = function() use (&$cache, $cache_key, $exists) {
if ($exists()) {
unset($cache[$cache_key]);
}
};
$persistence = newClosureTokenPersistence($set, $get, $delete, $exists);
Note: The format of the token data is a PHP associative array. You can flatten the array with serialize()
or json_encode()
or whatever else you want before storing it, but remember to decode it back to an array in get()
before returning it! Also, the above example is not very thread-safe, so if you have a high level of concurrency, you will need to find more atomic ways to handle this logic, or at least wrap things with try/catch
and handle things gracefully.
Please see the src/Persistence/ directory for more information on persistence.
Configuration options
The second argument of the client’s constructor is an array of configuration data. This can include URI template data
or special options that alter the client’s behavior:
Here’s an example showing how to set various configuration options, including default headers to send with each request,
default query string parameters to add to each request, a default auth scheme for each request, and a proxy to use for
each request. Values can be injected into the client’s base URL using variables from the configuration array.
Cookies
Specifies an associative array of cookies to add to the request.
Create a delete request to remove a server
To delete a server using Cloudways API, I need to create a Delete request in Guzzle through the following method. This is pretty similar to the above method, because it also requires two parameters, server id and label.
public function deleteServer($serverid,$label){try{$url = self::API_URL . “/server/$serverid”;$data = [‘server_id’ => $serverid,’label’ => $label];$header = array(‘Authorization’=>’Bearer ‘ . $this->accessToken);$response = $this->client->delete($url, array(‘query’ => $data,’headers’ => $header));return json_decode($response->getBody()->getContents());}catch (RequestException $e){$response = $this->StatusCodeHandling($e);return $response;}}
Try this in Postman or just refresh the page. The server will be deleted.
Create a put request to change server label
Now to change the server label, I need to create a PUT call in Guzzle. I will extend the class with a new method. Remember that server id and label are two necessary parameters that will be passed in the method.
public function changelabel($serverid,$label){try{$url = self::API_URL . “/server/$serverid”;$data = [‘server_id’ => $serverid,’label’ => $label];$header = array(‘Authorization’=>’Bearer ‘ . $this->accessToken);$response = $this->client->put($url, array(‘query’ => $data,’headers’ => $header));return json_decode($response->getBody()->getContents());}catch (RequestException $e){$response = $this->StatusCodeHandling($e);return $response;}}
Now in the index.php, put this condition beneath the foreach loop.
if($server->id == ‘71265’ && $server->label == ‘Cloned-php applications’){$label = ‘Cloudways Server’;$changelabel = $cw_api->changelabel($server->id,$label);}
When testing this in Postman, I will get the updated server label.
Creating a client
Clients create requests, send requests, and set responses on a request object. When instantiating a client object,
you can pass an optional “base URL” and optional array of configuration options. A base URL is a
:doc:
Creating requests with a client
A Client object exposes several methods used to create Request objects:
Debug
The debug option is used to show verbose cURL output for a transfer.
Emitters (guzzle 4 & 5)
Guzzle 4 & 5 use Event Subscribers, and this library includes OAuth2Subscriber for that purpose:
Events
The events option makes it easy to attach listeners to the various events emitted by a request object. The events
options must be an associative array mapping an event name to a Closure or array the contains a Closure and the
priority of the event.
Guzzle 4 & 5 vs guzzle 6
With the Guzzle 6 release, most of the library was refactored or completely rewritten, and as such, the integration of this library is different.
Guzzle authenticate with login form
Is it possible to authenticate a user with a login form for example login into GitHub via https://vhod-v-lichnyj-kabinet.ru/login
and then go to a page that needs login for example https://vhod-v-lichnyj-kabinet.ru/settings/profile
? I know packages like “FriendsOfPHP/Goutte” do this job but they use “symfony/browser-kit” package with guzzle. Is it possible to do this with guzzle only?
I tried this but the login does not authenticate:
<?php
use GuzzleHttpClient;
use GuzzleHttpExceptionRequestException;
use GuzzleHttpCookieFileCookieJar;
class guzzleRequest {
private $client;
private $jar;
private $body;
private $baseUrl;
private $host;
private $path;
public function __construct($base_url, $host) {
$this->path = __DIR__ . '/tmp/cookie.txt';
$this->jar = new FileCookieJar($this->path);
$this->client = new Client(['cookies' => $this->jar, 'allow_redirects' => TRUE]);
$this->baseUrl = $base_url;
$this->host = $host;
}
protected function makeRequest($page, $query = array(), $debug = false) {
try {
$options = [
'headers' => [
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36',
'Host' => $this->host,
'Referer' => $this->baseUrl . $page
]
];
if (!empty($query)) {
$options['query'] = $query;
}
$res = $this->client->request('GET', $this->baseUrl . $page, $options);
$this->body = $res->getBody();
return true;
} catch (RequestException $e) {
$this->body = $e->getResponse()->getBody();
return false;
}
}
public function getPage($page) {
$this->makeRequest($page);
return $this->body;
}
public function submitForm($page, $query = array(), $form_params = array(), $debug = false) {
try {
$options = [
'headers' => [
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36',
'Host' => $this->host,
'Referer' => $this->baseUrl . $page
]
];
if (!empty($query)) {
$options['query'] = $query;
}
if (!empty($form_params)) {
$options['form_params'] = $form_params;
}
$res = $this->client->request('POST', $this->baseUrl . $page, $options);
$this->body = $res->getBody();
$this->jar->save($this->path);
return true; //everything is fine
} catch (RequestException $e) {
$this->body = $e->getResponse()->getBody();
return false;
}
}
public function saveBody($mod = '') {
file_put_contents('tmp/output' . $mod . '.html', $this->body);
}
public function loadBody() {
$this->body = file_get_contents('test/output.html');
return $this->body;
}
}
and then call it:
require_once 'vendor/autoload.php';
require_once 'guzzleRequest.php';
$guzzleRequest = new guzzleRequest("https://github.com", "github.com");
$form_params = ["login" => "user", "password" => "pass"];
$guzzleRequest->submitForm('/session', array(), $form_params, true);
$guzzleRequest->getPage('/settings/profile');
$guzzleRequest->saveBody();
but in the output.html, the save page is “vhod-v-lichnyj-kabinet.ru/login” and the user not authenticated
Headers
Associative array of headers to apply to the request. When specified in the $options argument of a client creational
method (e.g. get(), post(), etc), the headers in the $options array will overwrite headers specified in the
$headers array.
Headers can be specified on a client to add default headers to every request sent by a client.
Install guzzle in php
The preferred way of installing Guzzle is Composer. If you haven’t installed Composer yet, download it from here
Now to install Guzzle, run the following command in SSH terminal:
Manually setting an access token
For a manually-obtained access token, you can use the NullGrantType and set the access token manually as follows:
Note that if the access token is not set using setAccessToken(), a kamermansOAuth2ExceptionReauthorizationException will be thrown since the NullGrantType has no way to get a new access token.
Params
The params options can be used to specify an associative array of data parameters to add to a request. Note that
these are not query string parameters.
Plugins
The plugins options makes it easy to attach an array of plugins to a request.
Plugins and events
Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications
powered by the
Symfony2 Event Dispatcher component. Any
event listener or subscriber attached to a Client object will automatically be attached to each request created by the
client.
Query
Associative array of query string parameters to the request. When specified in the $options argument of a client
creational method, the query string parameters in the $options array will overwrite query string parameters
specified in the $url.
Query string parameters can be specified on a client to add default query string parameters to every request sent by a
client.
Request options
Request options can be specified when creating a request or in the request.options parameter of a client. These
options can control various aspects of a request including: headers to send, query string data, where the response
should be downloaded, proxies, auth, etc.
Ssl_key
The ssl_key option lets you specify a file containing your PEM formatted private key, optionally protected by a password.
Note: your password is sensitive, keep the PHP script containing it safe.
This would typically be used in conjunction with the cert option.
Stream
Timeout / connect_timeout
You can specify the maximum number of seconds to allow for an entire transfer to take place before timing out using
the timeout request option. You can specify the maximum number of seconds to wait while trying to connect using the
connect_timeout request option. Set either of these options to 0 to wait indefinitely.
Usage
This plugin integrates seamlessly with Guzzle, transparently adding authentication to outgoing requests and optionally attempting re-authorization if the access token is no longer valid.
There are multiple grant types available like PasswordCredentials, ClientCredentials and AuthorizationCode.
Using the same cookie session for each request
Attach a GuzzlePluginCookieCookiePlugin to a client which will in turn add support for cookies to every request
created by a client, and each request will use the same cookie session:
Verify
Set to true to enable SSL certificate validation (the default), false to disable SSL certificate validation, or supply
the path to a CA bundle to enable verification using a custom certificate.
What you can do with the cloudways api
Cloudways is a managed hosting provider for PHP, Magento, WordPress and many other frameworks and CMS. It has an API that you could use for performing CRUD operations on servers and applications. Check out popular use cases of the Cloudways API to see how you could integrate it into your projects.
Sending requests
Requests can be sent by calling the send() method of a Request object, but you can also send requests using the
send() method of a Client.