|
| 1 | +# OAuth 2 decorator for the Symfony HTTP Client |
| 2 | + |
| 3 | +A decorator for the [Symfony HTTP Client](https://symfony.com/doc/current/http_client.html) that helps you call APIs endpoints protected with OAuth 2. |
| 4 | +It handles all the authentication protocol with the OAuth 2 server and let you focus solely on making your business API calls. |
| 5 | + |
| 6 | +Designed to be minimalist and lightweight, it has literally no dependency at all, apart the Symfony Contracts of course; and it requires only the PHP JSON extension. |
| 7 | + |
| 8 | +OAuth 2 is a relatively complex protocol which offers to authenticate in a wide variety of manners (called Grant Types in the OAuth jargon). |
| 9 | +This decorator aims to provide all standard Grant Types out of the box. Too often however, the OAuth 2 server you will have to authenticate to will not follow strict OAuth 2 standard. |
| 10 | +This is why the decorator has been designed such a way that every step of the authentication process is customizable. |
| 11 | + |
| 12 | +## Installation |
| 13 | + |
| 14 | + composer require benjaminfavre/oauth2-http-client |
| 15 | + |
| 16 | +## Usage |
| 17 | + |
| 18 | +```php |
| 19 | +use Symfony\Component\HttpClient\HttpClient; |
| 20 | +use BenjaminFavre\OAuthHttpClient\OAuthHttpClient; |
| 21 | +use BenjaminFavre\OAuthHttpClient\GrantType\ClientCredentialsGrantType; |
| 22 | + |
| 23 | +$httpClient = HttpClient::create(); |
| 24 | + |
| 25 | +// Here we will use the client credentials grant type but it could be any other grant type |
| 26 | +$grantType = new ClientCredentialsGrantType( |
| 27 | + $httpClient, |
| 28 | + 'https://github.com/login/oauth/access_token', // The OAuth server token URL |
| 29 | + 'the-client-id', |
| 30 | + 'the-client-password' |
| 31 | +); |
| 32 | + |
| 33 | +$httpClient = new OAuthHttpClient($httpClient, $grantType); |
| 34 | + |
| 35 | +// Then use $httpClient to make your API calls: |
| 36 | +// $httpClient->request(...); |
| 37 | +``` |
| 38 | + |
| 39 | +## How it works |
| 40 | + |
| 41 | +Each time you make an HTTP request, the decorator will: |
| 42 | +- Fetch an access token from cache or from the OAuth server if none is in cache; |
| 43 | +- Modify your request to add the access token (usually in a header); |
| 44 | +- Make the API call and return the response; |
| 45 | +- Optionally, try again with a new access token if the first API call failed because of token expiration. |
| 46 | + |
| 47 | +## Customization |
| 48 | + |
| 49 | +Implement any of the following interfaces in order to customize the relevant authentication step, and pass an instance of your class via the relevant Decorator setter. |
| 50 | + |
| 51 | +### GrantTypeInterface |
| 52 | + |
| 53 | +A class in charge of fetching an access token from the OAuth server. |
| 54 | +The decorator comes with four standard grant types: |
| 55 | +- AuthorizationCodeGrantType; |
| 56 | +- ClientCredentialsGrantType; |
| 57 | +- PasswordGrantType; |
| 58 | +- RefreshTokenGrantType. |
| 59 | + |
| 60 | +### TokensCacheInterface |
| 61 | + |
| 62 | +A class in charge of storing and fetching tokens from cache. |
| 63 | +By default, the decorator uses MemoryTokensCache that caches the tokens in memory. |
| 64 | + |
| 65 | +### RequestSignerInterface |
| 66 | + |
| 67 | +A class in charge of modifying the API request in order to add the access token. |
| 68 | +By default, the decorator uses BearerHeaderRequestSigner that adds the access token in the Authorization header. |
| 69 | +You can use the HeaderRequestSigner to add the access token in another header, or you can implement the interface for more customization. |
| 70 | + |
| 71 | +### ResponseCheckerInterface |
| 72 | + |
| 73 | +A class in charge of checking if the API call failed because of a token expiration. |
| 74 | +By default, the decorator uses StatusCode401ResponseChecker that identifies 401 response codes as the signal the access token needs to be renewed. |
| 75 | +It can lead to false positives (401 response code can be returned for other reasons than token expiration), so you can implement the interface if your OAuth server returns exploitable fine-grained error reasons. |
0 commit comments