{"id":15916911,"url":"https://github.com/kamermans/guzzle-oauth2-subscriber","last_synced_at":"2025-05-16T15:07:55.015Z","repository":{"id":37514808,"uuid":"92266554","full_name":"kamermans/guzzle-oauth2-subscriber","owner":"kamermans","description":"OAuth 2.0 Client for Guzzle 4, 5, 6 and 7 with PHP 5.4 - PHP 8.0 - no more dependency hell!","archived":false,"fork":false,"pushed_at":"2025-05-13T19:46:50.000Z","size":206,"stargazers_count":145,"open_issues_count":5,"forks_count":30,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-13T20:56:50.807Z","etag":null,"topics":["guzzle","guzzle-middleware","guzzlehttp","oauth","oauth2"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kamermans.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-24T08:04:29.000Z","updated_at":"2025-05-13T19:41:01.000Z","dependencies_parsed_at":"2024-06-18T11:08:12.469Z","dependency_job_id":"99161970-0414-4255-b1e5-a87b7e5a3849","html_url":"https://github.com/kamermans/guzzle-oauth2-subscriber","commit_stats":{"total_commits":101,"total_committers":16,"mean_commits":6.3125,"dds":0.2178217821782178,"last_synced_commit":"b2dc192f1ce9390d3c0e399ad0610fa1fddc17ea"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamermans%2Fguzzle-oauth2-subscriber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamermans%2Fguzzle-oauth2-subscriber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamermans%2Fguzzle-oauth2-subscriber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kamermans%2Fguzzle-oauth2-subscriber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kamermans","download_url":"https://codeload.github.com/kamermans/guzzle-oauth2-subscriber/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254553958,"owners_count":22090417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["guzzle","guzzle-middleware","guzzlehttp","oauth","oauth2"],"created_at":"2024-10-06T18:06:59.602Z","updated_at":"2025-05-16T15:07:50.005Z","avatar_url":"https://github.com/kamermans.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Guzzle OAuth 2.0 Subscriber\n\n\u003e Tested with Guzzle 4, 5, 6, 7 and PHP 7.1, 7.2, 7.3, 7.4, 8.0 and 8.1.\n\nThis is an OAuth 2.0 client for Guzzle which aims to be 100% compatible with Guzzle 4, 5, 6, 7 and all future versions within a single package.\nAlthough I love Guzzle, its interfaces keep changing, causing massive breaking changes every 12 months or so, so I have created this package\nto help reduce the dependency hell that most third-party Guzzle dependencies bring with them.  I wrote the official Guzzle OAuth 2.0 plugin\nwhich is still on the `oauth2` branch, [over at the official Guzzle repo](https://github.com/guzzle/oauth-subscriber/tree/oauth2), but I\nsee that they have dropped support for Guzzle \u003c v6 on `master`, which prompted me to split this back off to a separate package.\n\n## Features\n\n- Acquires access tokens via one of the supported grant types (code, client credentials,\n  user credentials, refresh token). Or you can set an access token yourself.\n- Supports refresh tokens (stores them and uses them to get new access tokens).\n- Handles token expiration (acquires new tokens and retries failed requests).\n- Allows storage and lookup of access tokens via callbacks\n\n\n## Installation\n\nThis project can be installed using Composer. Run `composer require kamermans/guzzle-oauth2-subscriber` or add the following to your `composer.json`:\n\n```javascript\n    {\n        \"require\": {\n            \"kamermans/guzzle-oauth2-subscriber\": \"~1.1\"\n        }\n    }\n```\n\n## Usage\n\nThis plugin integrates seamlessly with Guzzle, transparently adding authentication to outgoing requests and optionally attempting re-authorization if the access token is no longer valid.\n\nThere are multiple grant types available like `PasswordCredentials`, `ClientCredentials` and `AuthorizationCode`.\n\n### Guzzle 4 \u0026 5 vs Guzzle 6+\nWith the Guzzle 6 release, most of the library was refactored or completely rewritten, and as such, the integration of this library is different.\n\n#### Emitters (Guzzle 4 \u0026 5)\nGuzzle 4 \u0026 5 use **Event Subscribers**, and this library includes `OAuth2Subscriber` for that purpose:\n\n```php\n$oauth = new OAuth2Subscriber($grant_type);\n\n$client = new Client([\n    'auth' =\u003e 'oauth',\n]);\n\n$client-\u003egetEmitter()-\u003eattach($oauth);\n```\n\n#### Middleware (Guzzle 6+)\nStarting with Guzzle 6, **Middleware** is used to integrate OAuth, and this library includes `OAuth2Middleware` for that purpose:\n\n```php\n$oauth = new OAuth2Middleware($grant_type);\n\n$stack = HandlerStack::create();\n$stack-\u003epush($oauth);\n\n$client = new Client([\n    'auth'     =\u003e 'oauth',\n    'handler'  =\u003e $stack,\n]);\n```\n\nAlternatively, you can add the middleware to an existing Guzzle Client:\n\n```php\n$oauth = new OAuth2Middleware($grant_type);\n$client-\u003egetConfig('handler')-\u003epush($oauth);\n```\n\n\n### Client Credentials Example\nClient credentials are normally used in server-to-server authentication.  With this grant type, a client is requesting authorization in its own behalf, so there are only two parties involved.  At a minimum, a `client_id` and `client_secret` are required, although many services require a `scope` and other parameters.\n\nHere's an example of the client credentials method in Guzzle 4 and Guzzle 5:\n\n```php\nuse kamermans\\OAuth2\\GrantType\\ClientCredentials;\nuse kamermans\\OAuth2\\OAuth2Subscriber;\n\n// Authorization client - this is used to request OAuth access tokens\n$reauth_client = new GuzzleHttp\\Client([\n    // URL for access_token request\n    'base_url' =\u003e 'http://some_host/access_token_request_url',\n]);\n$reauth_config = [\n    \"client_id\" =\u003e \"your client id\",\n    \"client_secret\" =\u003e \"your client secret\",\n    \"scope\" =\u003e \"your scope(s)\", // optional\n    \"state\" =\u003e time(), // optional\n];\n$grant_type = new ClientCredentials($reauth_client, $reauth_config);\n$oauth = new OAuth2Subscriber($grant_type);\n\n// This is the normal Guzzle client that you use in your application\n$client = new GuzzleHttp\\Client([\n    'auth' =\u003e 'oauth',\n]);\n$client-\u003egetEmitter()-\u003eattach($oauth);\n$response = $client-\u003eget('http://somehost/some_secure_url');\n\necho \"Status: \".$response-\u003egetStatusCode().\"\\n\";\n```\n\nHere's the same example for Guzzle 6+:\n\n```php\nuse kamermans\\OAuth2\\GrantType\\ClientCredentials;\nuse kamermans\\OAuth2\\OAuth2Middleware;\nuse GuzzleHttp\\HandlerStack;\n\n// Authorization client - this is used to request OAuth access tokens\n$reauth_client = new GuzzleHttp\\Client([\n    // URL for access_token request\n    'base_uri' =\u003e 'http://some_host/access_token_request_url',\n]);\n$reauth_config = [\n    \"client_id\" =\u003e \"your client id\",\n    \"client_secret\" =\u003e \"your client secret\",\n    \"scope\" =\u003e \"your scope(s)\", // optional\n    \"state\" =\u003e time(), // optional\n];\n$grant_type = new ClientCredentials($reauth_client, $reauth_config);\n$oauth = new OAuth2Middleware($grant_type);\n\n$stack = HandlerStack::create();\n$stack-\u003epush($oauth);\n\n// This is the normal Guzzle client that you use in your application\n$client = new GuzzleHttp\\Client([\n    'handler' =\u003e $stack,\n    'auth'    =\u003e 'oauth',\n]);\n\n$response = $client-\u003eget('http://somehost/some_secure_url');\n\necho \"Status: \".$response-\u003egetStatusCode().\"\\n\";\n```\n\n### Authorization Code Example\nThere is a full example of using the `AuthorizationCode` grant type with a `RefreshToken` in the `examples/` directory.\n\n### Grant Types\nThe following OAuth grant types are supported directly, and you can always create your own by implementing `kamermans\\OAuth2\\GrantType\\GrantTypeInterface`:\n - `AuthorizationCode`\n - `ClientCredentials`\n - `PasswordCredentials`\n - `RefreshToken`\n\nEach of these takes a Guzzle client as the first argument.  This client is used to obtain or refresh your OAuth access token, out of band from the other requests you are making.\n\n### Request Signers\nThere are two cases where we need to *sign* an HTTP request: when adding client credentials to a request for a new access token, and when adding an access token to a request.\n\n#### Client Credentials Signers\nWhen 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.\n\nThere are two client credentials signers included in `kamermans\\OAuth2\\Signer\\ClientCredentials`:\n - `BasicAuth`: (default) Sends the credentials to the OAuth 2 server using HTTP Basic Auth in the `Authorization` header.\n - `PostFormData`: Sends the credentials to the OAuth 2 server using an HTTP Form Body (`Content-Type: application/x-www-form-urlencoded`).  The Client ID is stored in the field `client_id` and the Client Secret is stored in `client_secret`.  The field names can be changed by passing arguments to the constructor like this: `new PostFormData('MyClientId', 'MySecret');` (which would place the ID and secret into the fields `MyClientId` and `MySecret`).\n - `Json`: Sends the credentials to the OAuth 2 server using a JSON (`Content-Type: application/json`).  The Client ID is stored in the field `client_id` and the Client Secret is stored in `client_secret`.  The field names can be changed by passing arguments to the constructor like this: `new Json('MyClientId', 'MySecret');` (which would place the ID and secret into the fields `MyClientId` and `MySecret`).\n\nIf 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 `kamermans\\OAuth2\\Signer\\ClientCredentials\\SignerInterface`, for example:\n\n```php\nuse kamermans\\OAuth2\\Signer\\ClientCredentials\\SignerInterface;\n\nclass MyCustomAuth implements SignerInterface\n{\n    public function sign($request, $clientId, $clientSecret)\n    {\n        if (Helper::guzzleIs('~', 6)) {\n            $request = $request-\u003ewithHeader('x-client-id', $clientId);\n            $request = $request-\u003ewithHeader('x-client-secret', $clientSecret);\n            return $request;\n        }\n\n        $request-\u003esetHeader('x-client-id', $clientId);\n        $request-\u003esetHeader('x-client-secret', $clientSecret);\n        return $request;\n    }\n}\n```\n\n#### Access Token Signers\nWhen making a request to a REST endpoint protected by OAuth 2, we need to *sign* the request by adding the access token to it.  This library intercepts your requests, signs them with the current access token, and sends them on their way.\n\nThe two most common ways to sign a request are included in `kamermans\\OAuth2\\Signer\\AccessToken`:\n - `BearerAuth`: (default) Sends the access token using the HTTP `Authorization` header.\n - `BasicAuth`: Alias for `BearerAuth`. Don't use; exists for backwards compatibility only.\n - `QueryString`: Sends the access token by appending it to the query string.  The default query string field name is `access_token`, and if that field is already present in the request, it will be overwritten.  A different field name can be used by passing it to the constructor like this: `new QueryString('MyAccessToken')`, where `MyAccessToken` is the field name.\n\n\u003e Note: Use of the `QueryString` signer is discouraged because your access token is exposed in the URL.  Also, you should only connect to OAuth-powered services via `HTTPS` so your access token is encrypted in flight.\n\nYou can create a custom access token signer by implementing `kamermans\\OAuth2\\Signer\\AccessToken\\SignerInterface`.\n\n### Access Token Persistence\n\u003e 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!\n\nBy default, access tokens are not persisted anywhere.  There are some built-in mechanisms for caching / persisting tokens (in `kamermans\\OAuth2\\Persistence`):\n  - `NullTokenPersistence` (default) Disables persistence\n  - `FileTokenPersitence` Takes the path to a file in which the access token will be saved.\n  - `DoctrineCacheTokenPersistence` Takes a `Doctrine\\Common\\Cache\\Cache` object and optionally a key name (default: `guzzle-oauth2-token`) where the access token will be saved.\n  - `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.\n  - `Laravel5CacheTokenPersistence` Takes an `Illuminate\\Contracts\\Cache\\Repository` object and optionally a key name (default: `guzzle-oauth2-token`) where the access token will be saved.\n  - `ClosureTokenPersistence` Allows you to define a token persistence provider by providing closures to handle the persistence functions.\n\nIf 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.\n\nTo enable token persistence, you must use the `OAuth2Middleware::setTokenPersistence()` or `OAuth2Subscriber::setTokenPersistence()` method, like this:\n\n```php\nuse kamermans\\OAuth2\\Persistence\\FileTokenPersistence;\n\n$token_path = '/tmp/access_token.json';\n$token_persistence = new FileTokenPersistence($token_path);\n\n$grant_type = new ClientCredentials($reauth_client, $reauth_config);\n$oauth = new OAuth2Middleware($grant_type);\n$oauth-\u003esetTokenPersistence($token_persistence);\n```\n### Closure-Based Token Persistence\nThere 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.\n\n```php\n// We'll store everything in an array, but you can use any provider you want\n$cache = [];\n$cache_key = \"foo\";\n\n// Returns true if the item exists in cache\n$exists = function() use (\u0026$cache, $cache_key) {\n    return array_key_exists($cache_key, $cache);\n};\n\n// Sets the given $value array in cache\n$set = function(array $value) use (\u0026$cache, $cache_key) {\n    $cache[$cache_key] = $value;\n};\n\n// Gets the previously-stored value from cache (or null)\n$get = function() use (\u0026$cache, $cache_key, $exists) {\n    return $exists()? $cache[$cache_key]: null;\n};\n\n// Deletes the previously-stored value from cache (if exists)\n$delete = function() use (\u0026$cache, $cache_key, $exists) {\n    if ($exists()) {\n        unset($cache[$cache_key]);\n    }\n};\n\n$persistence = new ClosureTokenPersistence($set, $get, $delete, $exists);\n```\n\n\u003e 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.\n\nPlease see the `src/Persistence/` directory for more information on persistence.\n\n### Manually Setting an Access Token\nFor a manually-obtained access token, you can use the `NullGrantType` and set the access token manually as follows:\n\n```php\nuse kamermans\\OAuth2\\GrantType\\NullGrantType;\n\n$oauth = new OAuth2Middleware(new NullGrantType);\n$oauth-\u003esetAccessToken([\n\t// Your access token goes here\n    'access_token' =\u003e 'abcdefghijklmnop',\n\t// You can specify 'expires_in` as well, but it doesn't make much sense in this scenario\n\t// You can also specify 'scope' =\u003e 'list of scopes'\n]);\n```\n\nNote that if the access token is not set using `setAccessToken()`, a `kamermans\\OAuth2\\Exception\\ReauthorizationException` will be thrown since the `NullGrantType` has no way to get a new access token.\n\n### Using Refresh Tokens\nRefresh tokens are designed to allow a server to request a new access token on behalf of a user that is not present.  For example, if some fictional app `Angry Rodents` wants to post something to the social media site `Grillbook` on behalf of the user, `John Doe`, the `Angry Rodents` app needs an access token for `Grillbook`.  When `John Doe` first installs this app, it redirects him to the `Grillbook` site to authorize the `Angry Rodents` app to post on his behalf, and the `Angry Rodents` app receives an access token and a refresh token in the process.  Eventually the access token expires, but `Angry Rodents` cannot use the original method (redirecting the user to ask for permission) every time the token expires, so instead, it sends the refresh token to `Grillbook`, which returns a new access token (and possibly a new refresh token).\n\nTo use refresh tokens, you pass a `RefreshToken` grant type object as the second argument to `OAuth2Middleware` or `OAuth2Subscriber`.  Normally refresh tokens are only used in the interactive `AuthorizationCode` grant type (where the user is present), but it is also possible to use them with the other grant types (this is discouraged in the OAuth 2.0 spec).  For example, here we are using a refresh token with the `ClientCredentials` grant type:\n\n```php\n// This grant type is used to get a new Access Token and Refresh Token when\n//  no valid Access Token or Refresh Token is available\n$grant_type = new ClientCredentials($reauth_client, $reauth_config);\n\n// This grant type is used to get a new Access Token and Refresh Token when\n//  only a valid Refresh Token is available\n$refresh_grant_type = new RefreshToken($reauth_client, $reauth_config);\n\n// Tell the middleware to use the two grant types\n$oauth = new OAuth2Middleware($grant_type, $refresh_grant_type);\n```\n\n\u003e When using a refresh token to request a new access token, the server *may* send a new refresh token in the response.  If a new refresh token was sent, it will be saved, otherwise the old refresh token will be retained.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamermans%2Fguzzle-oauth2-subscriber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkamermans%2Fguzzle-oauth2-subscriber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkamermans%2Fguzzle-oauth2-subscriber/lists"}