Skip to content

Commit 1cebbf9

Browse files
committed
Create README
1 parent c120a6c commit 1cebbf9

File tree

4 files changed

+96
-7
lines changed

4 files changed

+96
-7
lines changed

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.

composer.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
{
2-
"name": "benjaminfavre/oauth-http-client",
2+
"name": "benjaminfavre/oauth2-http-client",
3+
"description": "A lightweight OAuth 2 decorator for the Symfony HTTP Client.",
4+
"keywords": ["symfony", "oauth", "http-client"],
5+
"homepage": "https://github.com/BenjaminFavre/oauth2-http-client",
6+
"license": "Apache-2.0",
7+
"authors": [
8+
{
9+
"name": "Benjamin Favre",
10+
"email": "[email protected]",
11+
"homepage": "https://github.com/BenjaminFavre"
12+
}
13+
],
314
"autoload": {
415
"psr-4": {"BenjaminFavre\\OAuthHttpClient\\": "src/"}
516
},
@@ -9,6 +20,9 @@
920
"symfony/http-client-contracts": "^2.3.1",
1021
"symfony/cache-contracts": "^2.2.0"
1122
},
23+
"provide": {
24+
"symfony/http-client-implementation": "^2.3.1"
25+
},
1226
"require-dev": {
1327
"phpunit/phpunit": "^9.4.3",
1428
"symfony/cache": "5.2.0",

src/OAuthHttpClient.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class OAuthHttpClient implements HttpClientInterface
2222
/** @var GrantTypeInterface */
2323
private $grant;
2424
/** @var RequestSignerInterface */
25-
private $modifier;
25+
private $signer;
2626
/** @var ResponseCheckerInterface */
2727
private $checker;
2828
/** @var TokensCacheInterface */
@@ -34,14 +34,14 @@ public function __construct(
3434
) {
3535
$this->client = $client;
3636
$this->grant = $grant;
37-
$this->modifier = new BearerHeaderRequestSigner();
37+
$this->signer = new BearerHeaderRequestSigner();
3838
$this->checker = new StatusCode401ResponseChecker();
3939
$this->cache = new MemoryTokensCache();
4040
}
4141

42-
public function setModifier(RequestSignerInterface $modifier): self
42+
public function setSigner(RequestSignerInterface $signer): self
4343
{
44-
$this->modifier = $modifier;
44+
$this->signer = $signer;
4545

4646
return $this;
4747
}
@@ -69,7 +69,7 @@ public function request(string $method, string $url, array $options = []): Respo
6969

7070
for ($tries = 0; $tries < 2; ++$tries) {
7171
$tokens = $this->cache->get($grant);
72-
$this->modifier->modify($options, $tokens->getAccessToken());
72+
$this->signer->modify($options, $tokens->getAccessToken());
7373
$response = $this->client->request($method, $url, $options);
7474

7575
if (!$this->checker->hasAuthenticationFailed($response)) {

src/TokensCache/TokensCacheInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace BenjaminFavre\OAuthHttpClient\TokensCache;
44

5-
use BenjaminFavre\OAuthHttpClient\GrantType\OAuthException;
5+
use BenjaminFavre\OAuthHttpClient\Exception\OAuthException;
66
use BenjaminFavre\OAuthHttpClient\GrantType\GrantTypeInterface;
77
use BenjaminFavre\OAuthHttpClient\GrantType\Tokens;
88

0 commit comments

Comments
 (0)