Skip to content
This repository was archived by the owner on Mar 23, 2024. It is now read-only.

Commit 08895f5

Browse files
committed
:octocat:
1 parent a07eab0 commit 08895f5

File tree

1 file changed

+140
-186
lines changed

1 file changed

+140
-186
lines changed

README.md

Lines changed: 140 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -28,120 +28,59 @@
2828
- PHP 7.2+
2929
- a [PSR-18](https://www.php-fig.org/psr/psr-18/) compatible HTTP client library of your choice
3030
- optional [PSR-17](https://www.php-fig.org/psr/psr-17/) compatible Request-, Response- and UriFactories
31-
- see [`chillerlan/php-oauth`](https://github.com/chillerlan/php-oauth) for already implemented providers
32-
33-
## Getting Started
34-
In order to instance an [`OAuthInterface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuthInterface.php) you you'll need to invoke a PSR-18 [`ClientInterface`](https://github.com/php-fig/http-client/blob/master/src/ClientInterface.php), a [`OAuthStorageInterface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Storage/OAuthStorageInterface.php) and `OAuthOptions` (a [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php)) objects first:
35-
```php
36-
use chillerlan\OAuth\Providers\<PROVIDER_NAMESPACE>\<PROVIDER>;
37-
use chillerlan\OAuth\{OAuthOptions, Storage\SessionStorage};
38-
use <PSR-18 HTTP Client>;
39-
40-
// OAuthOptions
41-
$options = new OAuthOptions([
42-
// OAuthOptions
43-
'key' => '<API_KEY>',
44-
'secret' => '<API_SECRET>',
45-
'callbackURL' => '<API_CALLBACK_URL>',
46-
]);
47-
48-
// a \Psr\Http\Client\ClientInterface
49-
$http = new HttpClient;
50-
51-
// OAuthStorageInterface
52-
// a persistent storage is required for authentication!
53-
$storage = new SessionStorage($options);
54-
55-
// an optional \Psr\LoggerInterface logger
56-
$logger = new Logger;
57-
58-
// invoke and use the OAuthInterface
59-
$provider = new Provider($http, $storage, $options, $logger);
60-
```
61-
62-
## Authentication
63-
The application flow may differ slightly depending on the provider; there's a working authentication example in the provider repository.
64-
65-
### Step 1: optional login link
66-
Display a login link and provide the user with information what kind of data you're about to access; ask them for permission to save the access token if needed.
67-
68-
```php
69-
echo '<a href="?login='.$provider->serviceName.'">connect with '.$provider->serviceName.'!</a>';
70-
```
71-
72-
### Step 2: redirect to the provider
73-
Redirect to the provider's login screen with optional arguments in the authentication URL, like permissions, scopes etc.
74-
```php
75-
// optional scopes for OAuth2 providers
76-
$scopes = [
77-
Provider::SCOPE_WHATEVER,
78-
];
79-
80-
if(isset($_GET['login']) && $_GET['login'] === $provider->serviceName){
81-
header('Location: '.$provider->getAuthURL(['extra-param' => 'val'], $scopes));
82-
}
83-
```
84-
85-
### Step 3: receive the token
86-
Receive the access token, save it, do whatever you need to do, then redirect to step 4
87-
88-
#### OAuth1
89-
```php
90-
if(isset($_GET['oauth_token']) && isset($_GET['oauth_verifier'])){
91-
$token = $provider->getAccessToken($_GET['oauth_token'], $_GET['oauth_verifier']);
92-
93-
// save & redirect...
31+
- see [`chillerlan/php-oauth-providers`](https://github.com/chillerlan/php-oauth-providers) for already implemented providers
32+
33+
## Installation
34+
**requires [composer](https://getcomposer.org)**
35+
36+
`composer.json` (note: replace `dev-master` with a version boundary)
37+
```json
38+
{
39+
"require": {
40+
"php": "^7.2",
41+
"chillerlan/php-oauth-core": "dev-master"
42+
}
9443
}
9544
```
45+
Profit!
9646

97-
#### OAuth2
98-
usage of the `<state>` parameter depends on the provider
99-
```php
100-
if(isset($_GET['code'])){
101-
$token = $provider->getAccessToken($_GET['code'], $_GET['state'] ?? null);
102-
103-
// save & redirect...
104-
}
105-
```
106-
107-
### Step 4: auth Granted
108-
After receiving the access token, go on and verify it then use the API.
109-
```php
110-
if(isset($_GET['granted']) && $_GET['granted'] === $provider->serviceName){
111-
$response = $provider->doStuff();
112-
113-
// ...
114-
}
115-
```
47+
## API
48+
### [`OAuthInterface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuthProvider.php)
49+
The `OAuthInterface` implements the PSR-18 [`ClientInterface`](https://www.php-fig.org/psr/psr-18/),
50+
the PSR-3[`LoggerAwareInterface`](https://www.php-fig.org/psr/psr-3/) as well as the
51+
[`ApiClientInterface`](https://github.com/chillerlan/php-magic-apiclient/blob/master/src/ApiClientInterface.php)
52+
and offers basic methods that are common to the OAuth 1/2 interfaces, all supplied in the abstract class [`OAuthProvider`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuthProvider.php).
11653

117-
## Call the Provider's API
118-
After successfully receiving the Token, we're ready to make API requests:
119-
```php
120-
// import a token to the OAuth token storage if needed
121-
$storage->storeAccessToken($provider->serviceName, (new AccessToken)->fromJSON($token_json));
122-
123-
// make a request
124-
$response = $provider->request(
125-
'/some/endpoint',
126-
['q' => 'param'],
127-
'POST',
128-
['data' => 'content'],
129-
['content-type' => 'whatever']
130-
);
131-
132-
// use the data: $response is a PSR-7 ResponseInterface
133-
$headers = $response->getHeaders();
134-
$data = $response->getBody()->getContents();
135-
```
54+
method | return | description
55+
------ | ------ | -----------
56+
`__construct(ClientInterface $http, OAuthStorageInterface $storage, SettingsContainerInterface $options, LoggerInterface $logger = null)` | - |
57+
`getAuthURL(array $params = null)` | PSR-7 `UriInterface` |
58+
`request(string $path, array $params = null, string $method = null, $body = null, array $headers = null)` | PSR-7 `ResponseInterface` |
59+
`setRequestFactory(RequestFactoryInterface $requestFactory)` | `OAuthInterface` | PSR-17
60+
`setStreamFactory(StreamFactoryInterface $streamFactory)` | `OAuthInterface` | PSR-17
61+
`setUriFactory(UriFactoryInterface $uriFactory)` | `OAuthInterface` | PSR-17
62+
`getRequestAuthorization(RequestInterface $request, AccessToken $token)` | PSR-7 `RequestInterface`
13663

137-
[chillerlan/php-httpinterface](https://github.com/chillerlan/php-httpinterface#psr-7-message-helpers) brings some convenience functions to handle a `ResponseInterface` (among other stuff).
64+
property | description
65+
-------- | -----------
66+
`$serviceName` | the classname for the current provider
67+
`$accessTokenURL` | the provider`s access token URL
68+
`$authURL` | the provider`s authentication token URL
69+
`$revokeURL` | an optional URL to revoke an access token (via API)
70+
`$userRevokeURL` | an optional link to the provider's user control panel where they can revoke the current token
71+
`$apiDocs` | a link to the provider's API docs
72+
`$applicationURL` | a link to the API/application credential generation page
73+
`$endpoints` | an `EndpointMapInterface` for the current provider
13874

139-
## Extensions
140-
In order to use a provider or storage, that is not yet supported, you'll need to implement the respective interfaces:
75+
### [`OAuth1Interface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuth1Provider.php)
76+
extends `OAuthInterface`
14177

142-
### [`OAuth1Interface`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Core/OAuth1Provider.php)
143-
The OAuth1 implementation is close to Twitter's specs and *should* work for most other OAuth1 services.
78+
method | return
79+
------ | ------
80+
`getRequestToken()` | `AccessToken`
81+
`getAccessToken(string $token, string $verifier)` | `AccessToken`
14482

83+
#### A minimal OAuth1 provider
14584
```php
14685
use chillerlan\OAuth\Core\OAuth1Provider;
14786

@@ -155,122 +94,137 @@ class MyOauth1Provider extends Oauth1Provider{
15594
}
15695
```
15796

158-
### [`OAuth2Interface`](https://github.com/chillerlan/php-oauth/tree/master/src/Providers/OAuth2Provider.php)
159-
[OAuth2 is a very straightforward... mess](https://hueniverse.com/oauth-2-0-and-the-road-to-hell-8eec45921529). Please refer to your provider's docs for implementation details.
160-
```php
161-
use chillerlan\OAuth\Core\OAuth2Provider;
162-
163-
class MyOauth2Provider extends Oauth2Provider implements ClientCredentials, CSRFToken, TokenExpires, TokenRefresh{
164-
165-
public const SCOPE_WHATEVER = 'whatever';
166-
167-
protected $apiURL = 'https://api.example.com';
168-
protected $authURL = 'https://example.com/oauth2/authorize';
169-
protected $accessTokenURL = 'https://example.com/oauth2/token';
170-
protected $clientCredentialsTokenURL = 'https://example.com/oauth2/client_credentials';
171-
protected $authMethod = self::HEADER_BEARER;
172-
protected $authHeaders = ['Accept' => 'application/json'];
173-
protected $apiHeaders = ['Accept' => 'application/json'];
174-
protected $scopesDelimiter = ',';
175-
176-
}
177-
```
178-
179-
### [`OAuthStorageInterface`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/OAuthStorageInterface.php)
180-
There are 2 different `OAuthStorageInterface`, refer to these for implementation details (extend `OAuthStorageAbstract`):
181-
- [`MemoryStorage`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/MemoryStorage.php): non-persistent, to store an existing token during script runtime and then discard it.
182-
- [`SessionStorage`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/SessionStorage.php): (half-)persistent, stores a token for as long a user's session is alive, e.g. while authenticating.
183-
184-
## API
185-
### [`OAuthInterface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuthProvider.php)
186-
Implements PSR-18 [`ClientInterface`](https://www.php-fig.org/psr/psr-18/) and PSR-3[`LoggerAwareInterface`](https://www.php-fig.org/psr/psr-3/).
187-
188-
method | return
189-
------ | ------
190-
`__construct(ClientInterface $http, OAuthStorageInterface $storage, SettingsContainerInterface $options)` | -
191-
`getAuthURL(array $params = null)` | PSR-7 `UriInterface`
192-
`request(string $path, array $params = null, string $method = null, $body = null, array $headers = null)` | PSR-7 `ResponseInterface`
193-
`setRequestFactory(RequestFactoryInterface $requestFactory)` | `OAuthInterface`
194-
`setStreamFactory(StreamFactoryInterface $streamFactory)` | `OAuthInterface`
195-
`setUriFactory(UriFactoryInterface $uriFactory)` | `OAuthInterface`
196-
197-
property | description
198-
-------- | -----------
199-
`$serviceName` | the classname for the current provider
200-
`$accessTokenURL` | the provider`s access token URL
201-
`$authURL` | the provider`s authentication token URL
202-
`$revokeURL` | an optional URL to revoke an access token (via API)
203-
`$userRevokeURL` | an optional link to the provider's user control panel where they can revoke the current token
20497

205-
### [`OAuth1Interface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuth1Provider.php)
206-
method | return
207-
------ | ------
208-
`getAccessToken(string $token, string $verifier, string $tokenSecret = null)` | `AccessToken`
209-
`getRequestToken()` | `AccessToken`
98+
### [`OAuth2Interface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuth2Provider.php)
99+
extends `OAuthInterface`
210100

211-
### [`OAuth2Interface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Core/OAuth2Provider.php)
212101
method | return
213102
------ | ------
214103
`getAccessToken(string $code, string $state = null)` | `AccessToken`
215104
`getAuthURL(array $params = null, $scopes = null)` | PSR-7 `UriInterface`
216105

217-
### `ClientCredentials`
106+
#### `ClientCredentials`
107+
The `ClientCredentials` interface indicates that the provider supports the [client credentials grant type](https://tools.ietf.org/html/rfc6749#section-4.4).
218108

219109
method | return
220110
------ | ------
221111
`getClientCredentialsToken(array $scopes = null)` | `AccessToken`
222112

223-
### `CSRFToken`
113+
#### `CSRFToken`
114+
The `CSRFToken` interface enables usage of the `<state>` parameter to mitigate [cross-site request forgery](https://tools.ietf.org/html/rfc6749#section-10.12) and automatically enforces it during authorization requests.
224115

225116
method | return
226117
------ | ------
227118
(protected) `checkState(string $state = null)` | `OAuth2Interface`
228119
(protected) `setState(array $params)` | array
229120

230-
### `TokenRefresh`
121+
#### `TokenRefresh`
122+
The `TokenRefresh` interface indicates if a provider supports usage of [refresh tokens](https://tools.ietf.org/html/rfc6749#section-10.4).
123+
The option setting `$tokenAutoRefresh` enables automatic refresh of expired tokens when using the `OAuthInterface::request()` or the PSR-18 `OAuthInterface::sendRequest()` methods to call the provider's API.
231124

232125
method | return
233126
------ | ------
234127
`refreshAccessToken(AccessToken $token = null)` | `AccessToken`
235128

236-
### `TokenExpires`
237-
method | return
238-
------ | ------
129+
#### A minimal OAuth2 provider
130+
```php
131+
use chillerlan\OAuth\Core\OAuth2Provider;
132+
133+
class MyOauth2Provider extends Oauth2Provider implements ClientCredentials, CSRFToken, TokenRefresh{
134+
135+
protected $apiURL = 'https://api.example.com';
136+
protected $authURL = 'https://example.com/oauth2/authorize';
137+
protected $accessTokenURL = 'https://example.com/oauth2/token';
138+
protected $clientCredentialsTokenURL = 'https://example.com/oauth2/client_credentials';
139+
protected $authMethod = self::HEADER_BEARER;
140+
protected $scopesDelimiter = ',';
141+
142+
}
143+
```
239144

240145
### [`OAuthStorageInterface`](https://github.com/chillerlan/php-oauth-core/blob/master/src/Storage/OAuthStorageAbstract.php)
146+
147+
The `OAuthStorageInterface` serves for storing access tokens and auth states (CSRF) on a per-user basis.
148+
The included implementations are intended for throwaway use during authentication or script runtime, please refer to these for implementation details (extend `OAuthStorageAbstract`):
149+
150+
- [`MemoryStorage`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/MemoryStorage.php): non-persistent, to store an existing token during script runtime and then discard it.
151+
- [`SessionStorage`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/SessionStorage.php): (half-)persistent, stores a token for as long a user's session is alive, e.g. while authenticating.
152+
153+
An example implementation for a persistent database storage with token encryption can be found over here: [`DBStorage`](https://github.com/chillerlan/php-oauth/blob/master/src/Storage/DBStorage.php).
154+
241155
method | return
242156
------ | ------
243-
`storeAccessToken(string $service, AccessToken $token)` | `OAuthStorageInterface`
157+
`storeAccessToken(string $service, AccessToken $token)` | bool
244158
`getAccessToken(string $service)` | `AccessToken`
245159
`hasAccessToken(string $service)` | bool
246-
`clearAccessToken(string$service)` | `OAuthStorageInterface`
247-
`clearAllAccessTokens()` | `OAuthStorageInterface`
248-
`storeCSRFState(string $service, string $state)` | `OAuthStorageInterface`
160+
`clearAccessToken(string$service)` | bool
161+
`clearAllAccessTokens()` | bool
162+
`storeCSRFState(string $service, string $state)` | bool
249163
`getCSRFState(string $service)` | string
250164
`hasCSRFState(string $service)` | bool
251-
`clearCSRFState(string $service)` | `OAuthStorageInterface`
252-
`clearAllCSRFStates()` | `OAuthStorageInterface`
253-
`toStorage(AccessToken $token)` | string
254-
`fromStorage(string $data)` | `AccessToken`
165+
`clearCSRFState(string $service)` | bool
166+
`clearAllCSRFStates()` | bool
167+
`toStorage(AccessToken $token)` | mixed
168+
`fromStorage($data)` | `AccessToken`
255169

256170
### [`AccessToken`](https://github.com/chillerlan/php-oauth-core/tree/master/src/Core/AccessToken.php)
171+
The `AccessToken` is a container to keep any token related data in one place. It extends the
172+
[`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php)
173+
and therefore offers all of its methods.
174+
257175
method | return | description
258176
------ | ------ | -----------
259-
`__construct(array $properties = null)` | - |
260-
`__set(string $property, $value)` | void | overrides `chillerlan\Traits\Container`
177+
`__construct(iterable $properties = null)` | - |
261178
`setExpiry(int $expires = null)` | `AccessToken` |
262-
`isExpired()` | `bool` |
263-
264-
property | type | default | allowed | description
265-
-------- | ---- | ------- | ------- | -----------
266-
`$requestToken` | string | null | * | OAuth1 only
267-
`$requestTokenSecret` | string | null | * | OAuth1 only
268-
`$accessTokenSecret` | string | null | * | OAuth1 only
269-
`$accessToken` | string | null | * |
270-
`$refreshToken` | string | null | * |
271-
`$extraParams` | array | `[]` | |
272-
`$expires` | int | `AccessToken::EOL_UNKNOWN` | |
273-
`$provider` | string | null | * |
179+
`isExpired()` | bool |
180+
181+
inherited from `SettingsContainerInterface`:
182+
183+
method | return | description
184+
------ | ------ | -----------
185+
`__get(string $property)` | mixed |
186+
`__set(string $property, $value)` | void | calls `$this->{'set_'.$property}($value)` if such a method exists
187+
`__isset(string $property)` | bool |
188+
`__unset(string $property)` | void |
189+
`__toString()` | string | a JSON string
190+
`toArray()` | array |
191+
`fromIterable(iterable $properties)` | `SettingsContainerInterface` |
192+
`toJSON(int $jsonOptions = null)` | string | accepts [JSON options constants](http://php.net/manual/json.constants.php)
193+
`fromJSON(string $json)` | `SettingsContainerInterface` |
194+
195+
property | type | default | description
196+
-------- | ---- | ------- | -----------
197+
`$accessTokenSecret` | string | `null` | OAuth1 only
198+
`$accessToken` | string | `null` |
199+
`$refreshToken` | string | `null` |
200+
`$extraParams` | array | `[]` |
201+
`$expires` | int | `AccessToken::EOL_UNKNOWN` |
202+
`$provider` | string | `null` |
203+
204+
### [`OAuthOptions`](https://github.com/chillerlan/php-oauth-core/blob/master/src/OAuthOptions.php)
205+
`OAuthOptions` is a [`SettingsContainerInterface`](https://github.com/chillerlan/php-settings-container/blob/master/src/SettingsContainerInterface.php)
206+
that uses the plug-in traits [`OAuthOptionsTrait`](https://github.com/chillerlan/php-oauth-core/blob/master/src/OAuthOptionsTrait.php)
207+
and [`HTTPOptionsTrait`](https://github.com/chillerlan/php-httpinterface/blob/master/src/HTTPOptionsTrait.php) to provide settings for a provider.
208+
209+
property | type | default | description
210+
-------- | ---- | ------- | -----------
211+
`$key` | string | `null` | The application key (or id) given by your provider (see [supported providers](https://github.com/chillerlan/php-oauth-providers#supported-providers))
212+
`$secret` | string | `null` | The application secret given by your provider
213+
`$callbackURL` | string | `null` | The callback URL associated with your application
214+
`$sessionStart` | bool | `true` | Whether or not to start the session when [session storage](https://github.com/chillerlan/php-oauth-core/tree/master/src/Storage/SessionStorage.php) is used
215+
`$sessionTokenVar` | string | 'chillerlan-oauth-token' | The session array key for token storage
216+
`$sessionStateVar` | string | 'chillerlan-oauth-state' | The session array key for <state> storage (OAuth2)
217+
`$tokenAutoRefresh` | bool | `true` | Whether or not to automatically refresh access tokens (OAuth2)
218+
219+
from `HTTPOptionsTrait`:
220+
221+
property | type | default | description
222+
-------- | ---- | ------- | -----------
223+
`$user_agent` | string | |
224+
`$curl_options` | array | `[]` | https://php.net/manual/function.curl-setopt.php
225+
`$ca_info` | string | `null` | https://curl.haxx.se/docs/caextract.html
226+
`$ssl_verifypeer` | bool | `true` | see CURLOPT_SSL_VERIFYPEER
227+
274228

275229
# Disclaimer
276230
OAuth tokens are secrets and should be treated as such. Store them in a safe place,

0 commit comments

Comments
 (0)