Skip to content

Commit

Permalink
📖
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed May 14, 2024
1 parent 647a43d commit a603fc3
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 7 deletions.
1 change: 0 additions & 1 deletion docs/Development/Using-examples.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ The markdown sources for the [Read the Docs online manual](https://php-oauth.rea

- [Quickstart](./Usage/Quickstart.md)
- [Authorization flow](./Usage/Authorization.md)
- [Using the examples](./Usage/Using-examples.md)


### Development

- [Create a Provider](./Development/Create-provider.md)
- [Additional functionality](./Development/Additional-functionality.md)
- [Running tests](./Development/Test-suite.md)
- [Using the examples](./Development/Using-examples.md)


### Appendix
Expand Down
6 changes: 3 additions & 3 deletions docs/Usage/Authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ echo '<a href="?route=oauth-login">connect with GitHub!</a>';

The method `OAuthInterface::getAuthorizationURL()` takes two (optional) parameters:

- `$params`: this array contains additional query parameters that will be added to the URL query (provider dependent)
- `$params`: this array contains additional query parameters that will be added to the URL query (service dependent)
- `$scopes`: this array contains all scopes that will be used for this authorization

When the user clicks the log-in link, just execute a `header()` to the provider's authorization URL.
Expand All @@ -30,7 +30,7 @@ if($route === 'oauth-login'){
header('Location: '.$provider->getAuthorizationURL($params, $scopes));

// -> https://github.com/login/oauth/authorize?client_id=<client_id>
// &redirect_uri=https%3A%2F%2Fexample.com%2Fcallback%2F&response_type=code
// &redirect_uri=https%3A%2F%2Fexample.com%2Foauth%2F&response_type=code
// &scope=<scopes>&state=<state>&type=web_server
}
```
Expand All @@ -47,7 +47,7 @@ while the similar `OAuth2Interface::getAccessToken()` takes two parameters `$cod

### OAuth2

In our GitHub OAuth2 example we're now receiving the incoming callback to `https://example.com/callback/?code=<code>&state=<state>`.
In our GitHub OAuth2 example we're now receiving the incoming callback to `https://example.com/oauth/?code=<code>&state=<state>`.
The `getAccessToken()` method initiates a backend request to the provider's server to exchange the temporary credentials for an access token:

```php
Expand Down
56 changes: 55 additions & 1 deletion docs/Usage/Quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $options->sessionStart = true;
$storage = new SessionStorage($options);
```


### Using existing tokens

Most of the time you'll probably just want to use/import an existing access token to use an API on the user's behalf.
Expand Down Expand Up @@ -79,11 +80,36 @@ $provider->storeAccessToken($token);
To invoke an OAuth provider, you'll need a `OAuthOptions` instance, a [PSR-18](https://www.php-fig.org/psr/psr-18/) `ClientInterface` (such as [`guzzlehttp/guzzle`](https://github.com/guzzle/guzzle) or [`chillerlan/php-httpinterface`](https://github.com/chillerlan/php-httpinterface)),
along with the [PSR-17](https://www.php-fig.org/psr/psr-17/) factories `RequestFactoryInterface`, `StreamFactoryInterface` and `UriFactoryInterface`. An `OAuthStorageInterface` and a PSR-3 logger instance are optional.

First you'll need a PSR-18 compatible HTTP client, it should (at least) support [CURLOPT_SSL_VERIFYPEER](https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html) and have it enabled,
for which it needs a valid certificate (or [certificate bundle](https://curl.se/docs/caextract.html)).

**chillerlan/HTTP**

```php
$httpOptions = new \chillerlan\HTTP\HTTPOptions([
'ca_info' => '/path/to/cacert.pem',
'user_agent' => OAuthInterface::USER_AGENT,
]);

$http = new \chillerlan\HTTP\CurlClient(new ResponseFactory, $httpOptions);
```

Let's invoke a `GitHub` provider:
**GuzzleHttp**

```php
$httpOptions = [
'verify' => '/path/to/cacert.pem',
'headers' => [
'User-Agent' => OAuthInterface::USER_AGENT,
],
];

$http = new \GuzzleHttp\Client($httpOptions);
```

Now let's invoke a `GitHub` provider:

```php
// now we can invoke the provider
$provider = new GitHub(
$options,
Expand All @@ -95,3 +121,31 @@ $provider = new GitHub(
);
```


### Provider factory

Invoking a provider can be a bit chunky and perhaps gets messy as soon as you're using more than one OAuth service in your project.
In that case you can use the `OAuthProviderFactory` for convenience:

```php
// invoke the provider factory with the common PSR instances
$providerFactory = new OAuthProviderFactory(
$http,
new RequestFactory,
new StreamFactory,
new UriFactory,
$logger, // optional
);

// invoke the provider instance - the $options and $storage params are optional
$provider = $providerFactory->getProvider(GitHub::class, $options, $storage);
```

Additionally, the provider factory offers convenience methods to set a different logger instance and to get each of the PSR-17 factories:

```php
$providerFactory->setLogger(new NullLogger);
$providerFactory->getRequestFactory();
$providerFactory->getStreamFactory();
$providerFactory->getUriFactory();
```
107 changes: 107 additions & 0 deletions docs/Usage/Using-examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Using the examples

OAuth is not exactly trivial and so is live testing an OAuth flow to make sure the implementation and all its details work as expected.
The examples - specifically [the get-token examples](https://github.com/chillerlan/php-oauth/tree/main/examples/get-token) -
are abstracted and condensed as far as possible to make using them as convenient as it can get.


## Requirements

### Server

Due to the nature of OAuth callbacks, you will need a webserver with public access, or rather, that is accepted as callback URL
by the service you're about to test, so `http://127.0.0.1/oauth/` will *definitely not* work - we'll assume
`https://example.com/oauth/` as the public callback URL throughout the examples.

Further we'll assume that `/var/www/` (with an associated user `webmaster`) is the directory that holds all web related files and dependencies,
and `/var/www/htdocs/` is the root of the public website, which translates to `https://example.com/`, hence `/var/www/htdocs/oauth/` becomes the OAuth callback entrypoint at `https://example.com/oauth/`.
A web framework would probably just have `/var/www/htdocs/index.php` as its entry point and route all requests through it,
but that is not focus of this example.


### Dependencies

To install the required dependencies, create a `composer.json` in `/var/www/` with the following content and run `composer install` (as user `webmaster`):

```json
{
"require": {
"php": "^8.1",
"chillerlan/php-dotenv": "^3.0",
"chillerlan/php-oauth": "^1.0",
"guzzlehttp/guzzle": "^7.8",
"monolog/monolog": "^3.5"
}
}
```

After that, copy the `examples` directory in the library root to `/var/www/oauth-examples/`.


### Configuration

We'll store the configuration files in the user directory under `/home/webmaster/oauth-config/`.
The `FileStorage` in the `OAuthExampleProviderFactory` expects a `.filestorage` directory in the configuration directory
with permissions set to at least `0755`, otherwise PHP's `is_writable()` will fail.

The cacert is also expected in the configuration, so we'll fetch a fresh one directly into it:

```shell
curl -o /home/webmaster/oauth-config/cacert.pem https://curl.se/ca/cacert.pem
```

Finally, we need a `.env` file that contains the provider configuration. We'll [create an application on GitHub](https://github.com/settings/developers)
and save the credentials - the naming convention is `<prefix>_<KEY|SECRET|CALLBACK_URL>` where the prefix is `OAuthInterface::IDENTIFIER`.

```
GITHUB_KEY=<Client ID>
GITHUB_SECRET=<Client secret>
GITHUB_CALLBACK_URL=https://example.com/oauth/
```


## Run the authorization flow

The call chain starts with the [`index.php`](https://github.com/chillerlan/php-oauth/blob/main/public/index.php) in `/var/www/htdocs/oauth/`.
We'll need to adjust it to our example configuration from before:

```php
$AUTOLOADER = '/var/www/vendor/autoload.php';
$CFGDIR = '/home/webmaster/oauth-config/';
$ENVFILE = '.env';

// additional parameters
$PARAMS = [];
// scopes to use with the given provider
$SCOPES = [
GitHub::SCOPE_USER,
GitHub::SCOPE_PUBLIC_REPO,
GitHub::SCOPE_GIST,
];

// uncomment in case something goes wrong
#error_reporting(E_ALL);
#ini_set('display_errors', 1);

require_once '/var/www/oauth-examples/get-token/GitHub.php';
```

You can now navigate to `https://example.com/oauth/` where you will be greeted with a link "Connect with GitHub!".

### Call chain

Let's break down what happens behind the scenes:

1. the `index.php` initializes a set of variables and includes an example from `/var/www/oauth-examples/get-token/`, here `GitHub.php`
2. `<provider>.php` includes [`/var/www/oauth-examples/provider-example-common.php`](https://github.com/chillerlan/php-oauth/blob/main/examples/provider-example-common.php), which:
- includes the composer autoloader given through `$AUTOLOADER`
- invokes the PSR-18 HTTP client, which is available as `$http`
- invokes the [`OAuthExampleProviderFactory`](https://github.com/chillerlan/php-oauth/blob/main/examples/OAuthExampleProviderFactory.php), which is available as `$factory`
3. the OAuth provider is invoked via `$factory->getProvider(<provider>::class)` in `<provider>.php` and becomes available as `$provider`
4. `<provider>.php` includes either `_flow-oauth1.php` or `_flow-oauth2.php` from `/var/www/oauth-examples/get-token/`
5. the [authorization flow](./Authorization.md) is executed:
- redirect to the URL received from `$provider->getAuthorizationURL($PARAMS, $SCOPES)`
- the token request is called with the data from the incoming callback via `$provider->getAccessToken(...)`
- the access token is stored under `/home/webmaster/oauth-config/.filestorage` and is displayed in the output once access is granted

Profit!
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This work is licensed under the Creative Commons Attribution 4.0 International (

Usage/Quickstart.md
Usage/Authorization.md
Usage/Using-examples.md

.. toctree::
:maxdepth: 3
Expand All @@ -34,7 +35,6 @@ This work is licensed under the Creative Commons Attribution 4.0 International (
Development/Create-provider.md
Development/Additional-functionality.md
Development/Test-suite.md
Development/Using-examples.md

.. toctree::
:maxdepth: 3
Expand Down

0 comments on commit a603fc3

Please sign in to comment.