chillerlan / php-oauth-providers
OAuth 1/2 Provider implementations for chillerlan/php-oauth-core. PHP 7.2+
Fund package maintenance!
Ko Fi
Requires
- php: ^7.2
- ext-json: *
- ext-simplexml: *
- chillerlan/php-oauth-core: ^3.0
- psr/http-client: ^1.0
- psr/http-message: ^1.0
Requires (Dev)
- chillerlan/php-dotenv: ^1.0
- phpunit/phpunit: ^8.4
This package is auto-updated.
Last update: 2021-01-06 05:41:06 UTC
README
Requirements
- PHP 7.2+
- a PSR-18 compatible HTTP client library of your choice (there is one included, though)
- optional PSR-17 compatible Request-, Response- and UriFactories
For documentation of the core components see chillerlan/php-oauth-core
.
Installation
requires composer
composer.json
(note: replace dev-master
with a version boundary)
{ "require": { "php": "^7.2", "chillerlan/php-oauth-providers": "dev-master" } }
Profit!
Getting Started
In order to instance a provider (OAuthInterface
) you you'll need to invoke a
PSR-18 ClientInterface
,
an OAuthStorageInterface
and OAuthOptions
(a SettingsContainerInterface
) objects first:
use chillerlan\OAuth\Providers\<PROVIDER_NAMESPACE>\<PROVIDER> as Provider; use chillerlan\OAuth\{OAuthOptions, Storage\SessionStorage}; use <PSR-18 HTTP Client>; $options = new OAuthOptions([ 'key' => '<API_KEY>', 'secret' => '<API_SECRET>', 'callbackURL' => '<API_CALLBACK_URL>', ]); // a PSR-18 http client $http = new HttpClient; // OAuthStorageInterface // a persistent storage is required for authentication! $storage = new SessionStorage($options); // an optional PSR-3 logger $logger = new Logger; // invoke and use the OAuthInterface $provider = new Provider($http, $storage, $options, $logger);
Authentication
The application flow may differ slightly depending on the provider; there's a working authentication example in the provider repository.
Step 1: optional login link
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.
echo '<a href="?login='.$provider->serviceName.'">connect with '.$provider->serviceName.'!</a>';
Step 2: redirect to the provider
Redirect to the provider's login screen with optional arguments in the authentication URL, like permissions, scopes etc.
// additional request parameters $params = [ 'extra-param' => 'val', ]; // optional scopes for OAuth2 providers // you may want to save the used scopes along with the received token $scopes = [ Provider::SCOPE_WHATEVER, ]; header('Location: '.$provider->getAuthURL($params, $scopes));
Step 3: receive the token
Receive the access token and save it, do whatever you need to do (e.g. save scopes with the token), then redirect to step 4.
OAuth1
// save token & redirect... $token = $provider->getAccessToken($_GET['oauth_token'], $_GET['oauth_verifier']);
OAuth2
Usage of the <state>
parameter is enforced through the CSRFToken
interface if the provider implements it.
// save token & redirect... $token = $provider->getAccessToken($_GET['code'], $_GET['state'] ?? null);
Step 4: auth granted
After receiving the access token, go on and verify it then use the API.
$response = $provider->request('/do/stuff', 'GET'); // or using the magic API $response = $provider->doStuff(); // ...
Call the Provider's API
After successfully receiving the Token, we're ready to make API requests:
$storage = new MemoryStorage; // import a token to the OAuth token storage if needed $storage->storeAccessToken($provider->serviceName, (new AccessToken)->fromJSON($token_json)); // make a request $response = $provider->request( '/some/endpoint', ['q' => 'param'], 'POST', ['data' => 'content'], ['content-type' => 'whatever'] ); // use the data: $response is a PSR-7 ResponseInterface $headers = $response->getHeaders(); $data = $response->getBody()->getContents();
The included chillerlan/php-httpinterface brings some convenience functions to handle a ResponseInterface
(among other stuff).
Another way to call the provider API is to use the methods provided by an EndpointMapInterface
.
See below for more information.
Provider implementation
In order to use a provider that is not yet supported, you'll need to implement the respective interfaces. The abstract providers already implement everything necessary, so that in most cases you only need to set the required URLs in order to get started.
Additionally to the provider specific properties there are several common ones, most importantly $apiURL
(required),
which sets the base URL for the provider's API, as well as $authHeaders
and $apiHeaders
that can be used to provide extra headers which should be included in each call.
OAuth1Interface
A minimal OAuth1 implementation requires $requestTokenURL
, $authURL
, $accessTokenURL
like follows:
use chillerlan\OAuth\Core\OAuth1Provider; class MyOauth1Provider extends Oauth1Provider{ protected $apiURL = 'https://api.example.com'; protected $requestTokenURL = 'https://example.com/oauth/request_token'; protected $authURL = 'https://example.com/oauth/authorize'; protected $accessTokenURL = 'https://example.com/oauth/access_token'; }
Example implementations for OAuth1 providers: Discogs, Twitter, Flickr
OAuth2Interface
OAuth2 is a very straightforward... mess. Please refer to your provider's docs for implementation details.
A minimum OAuth2 implementation requires $authURL
and $accessTokenURL
.
If the provider allows fetching client tokens, an optional $clientCredentialsTokenURL
can be set (in case it differs from $accessTokenURL
).
An $authMethod
needs to be set if it differs from the "standard" header Authorization: Bearer <TOKEN>
.
There are constants for the most common auth methods in OAuth2Interface.
Finally, a $scopesDelimiter
can be set if it differs from the default ' '
(space).
There are several interfaces that can be implemented by OAuth2 providers:
ClientCredentials
- allows to fetch client credentials access tokensCSRFToken
- enforces the usage/verification of the<state>
parameter during authenticationTokenRefresh
- allows refreshing expired tokens during requests
use chillerlan\OAuth\Core\OAuth2Provider; class MyOauth2Provider extends Oauth2Provider implements ClientCredentials, CSRFToken, TokenRefresh{ public const SCOPE_WHATEVER = 'whatever'; protected $apiURL = 'https://api.example.com'; protected $authURL = 'https://example.com/oauth2/authorize'; protected $accessTokenURL = 'https://example.com/oauth2/token'; protected $clientCredentialsTokenURL = 'https://example.com/oauth2/client_credentials'; protected $authMethod = self::HEADER_BEARER; protected $authHeaders = ['Accept' => 'application/json']; protected $apiHeaders = ['Accept' => 'application/json']; protected $scopesDelimiter = ','; }
Example implementations for OAuth2 providers: Spotify, Mastodon, MusicBrainz
MagicAPI
The magic API client is basically a container holding arrays with information about each endpoint of an API that translate into provider methods.
It requires an implementation of a __call()
method that turns the given parameters into requests and returns the result, a PSR-7 ResponseInterface
.
class ProviderEndpoints extends EndpointMap{ // a common base path, useful for versioning etc. protected $API_BASE = '/v1'; protected $myEndpoint = [ // the path to your endpoint, path elements that are values are replaced by numbered placeholders (see sprintf()) 'path' => '/my/endpoint/%1$s', // the request method 'method' => 'GET', // additional query elements, listed are the names of the query parameters 'query' => ['q'], // the path elemnts corresponding to the placeholders in "path" 'path_elements' => ['path'], // names of the post/patch/put body elements (if any) 'body' => null, // additional request headers 'headers' => null, ]; }
The above endpoint example would then translate to:
$provider->myEndpoint(string $path, array $query = ['q' => null]);
See the Spotify
provider ,
its Endpoint map
and the live API tests for examples.
To ease IDE type hinting for magic methods, there's a docblock generator over here.
Supported Providers
A list of already implemented Providers.
Provider | API keys | revoke access | OAuth | ClientCredentials |
---|---|---|---|---|
Amazon | link | 2 | ||
BattleNet | link | link | 2 | ✓ |
BigCartel | link | link | 2 | |
Bitbucket | link | 2 | ✓ | |
Deezer | link | link | 2 | |
DeviantArt | link | link | 2 | ✓ |
Discogs | link | link | 1 | |
Discord | link | 2 | ✓ | |
Flickr | link | link | 1 | |
Foursquare | link | link | 2 | |
GitHub | link | link | 2 | |
GitLab | link | 2 | ✓ | |
Gitter | link | 2 | ||
link | link | 2 | ||
Youtube | link | link | 2 | |
GuildWars2 | link | link | 2 | |
Imgur | link | link | 2 | |
link | link | 2 | ||
LastFM | link | link | - | |
MailChimp | link | 2 | ||
Mastodon | link | 2 | ||
MicrosoftGraph | link | link | 2 | |
Mixcloud | link | link | 2 | |
MusicBrainz | link | link | 2 | |
NPROne | link | 2 | ||
OpenCaching | link | link | 1 | |
OpenStreetmap | link | 1 | ||
Patreon1 | link | 2 | ||
Patreon2 | link | 2 | ||
PayPal | link | 2 | ✓ | |
PayPalSandbox | link | 2 | ✓ | |
Slack | link | link | 2 | |
SoundCloud | link | link | 2 | |
Spotify | link | link | 2 | ✓ |
Stripe | link | link | 2 | |
Tumblr | link | link | 1 | |
Twitch | link | link | 2 | ✓ |
link | link | 1 | ||
TwitterCC | link | link | 2 | ✓ |
Vimeo | link | link | 2 | ✓ |
Wordpress | link | link | 2 |
Disclaimer
OAuth tokens are secrets and should be treated as such. Store them in a safe place,
consider encryption.
I won't take responsibility for stolen auth tokens. Use at your own risk.