chillerlan/php-oauth-providers

OAuth 1/2 Provider implementations for chillerlan/php-oauth-core. PHP 7.2+

This package is auto-updated.

Last update: 2021-01-06 05:41:06 UTC


README

Packagist version License Travis CI CodeCov Scrunitizer CI Packagist downloads PayPal donate

Requirements

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 tokens
  • CSRFToken - enforces the usage/verification of the <state> parameter during authentication
  • TokenRefresh - 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
Google link link 2
Youtube link link 2
GuildWars2 link link 2
Imgur link link 2
Instagram 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
Twitter 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.