diff --git a/monorepo-builder.yml b/monorepo-builder.yml index 364ff82c9..7eda13aa1 100644 --- a/monorepo-builder.yml +++ b/monorepo-builder.yml @@ -30,6 +30,7 @@ parameters: src/Cheddar: 'git@github.com:SocialiteProviders/Cheddar.git' src/ClaveUnica: 'git@github.com:SocialiteProviders/ClaveUnica.git' src/Clerk: 'git@github.com:SocialiteProviders/Clerk.git' + src/Clover: 'git@github.com:SocialiteProviders/Clover.git' src/Cognito: 'git@github.com:SocialiteProviders/Cognito.git' src/Coinbase: 'git@github.com:SocialiteProviders/Coinbase.git' src/ConstantContact: 'git@github.com:SocialiteProviders/ConstantContact.git' diff --git a/src/Clover/CloverExtendSocialite.php b/src/Clover/CloverExtendSocialite.php new file mode 100644 index 000000000..a740ab060 --- /dev/null +++ b/src/Clover/CloverExtendSocialite.php @@ -0,0 +1,13 @@ +extendSocialite(Provider::IDENTIFIER, Provider::class); + } +} diff --git a/src/Clover/Provider.php b/src/Clover/Provider.php new file mode 100644 index 000000000..f1c7a93bc --- /dev/null +++ b/src/Clover/Provider.php @@ -0,0 +1,126 @@ +getHttpClient()->post($this->getTokenUrl(), [ + RequestOptions::HEADERS => $this->getTokenHeaders($code), + RequestOptions::JSON => $this->getTokenFields($code), + ]); + + return json_decode($response->getBody(), true); + } + + protected function getApiDomain(): string + { + return match ($this->getConfig('environment')) { + 'sandbox' => 'sandbox.dev.clover.com', + default => 'www.clover.com', + }; + } + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state): string + { + return $this->buildAuthUrlFromBase( + sprintf('https://%s/oauth/v2/authorize', $this->getApiDomain()), + $state + ); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl(): string + { + $domain = match ($this->getConfig('environment')) { + 'sandbox' => 'apisandbox.dev.clover.com', + default => 'api.clover.com', + }; + + return sprintf('https://%s/oauth/v2/token', $domain); + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken($token) + { + $response = $this->getHttpClient()->get(sprintf( + 'https://%s/v3/merchants/%s/employees/%s', + $this->getApiDomain(), + $this->request->query('merchant_id'), + $this->request->query('employee_id'), + ), [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token, + ], + ]); + + return json_decode((string) $response->getBody(), true); + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + return (new User())->setRaw($user)->map([ + 'id' => $user['id'], + 'nickname' => $user['name'], + 'name' => $user['name'], + 'email' => $user['email'], + 'avatar' => null, + ]); + } + + /** + * Get the expires in from the token response body. + * + * @param array $body + * @return string + */ + protected function parseExpiresIn($body) + { + return (string) (Arr::get($body, 'access_token_expiration') - time()); + } +} diff --git a/src/Clover/README.md b/src/Clover/README.md new file mode 100644 index 000000000..34284703b --- /dev/null +++ b/src/Clover/README.md @@ -0,0 +1,72 @@ +# Clover + +```bash +composer require socialiteproviders/clover +``` + +## Installation & Basic Usage + +Please see the [Base Installation Guide](https://socialiteproviders.com/usage/), then follow the provider specific instructions below. + +Ensure the app has permission to read employees. + +### Add configuration to `config/services.php` + +```php +'clover' => [ + 'client_id' => env('CLOVER_CLIENT_ID'), + 'client_secret' => env('CLOVER_CLIENT_SECRET'), + 'redirect' => env('CLOVER_REDIRECT_URI') + 'environment' => env('CLOVER_ENVIRONMENT', 'production'), +], +``` + +### Add provider event listener + +Configure the package's listener to listen for `SocialiteWasCalled` events. + +Add the event to your `listen[]` array in `app/Providers/EventServiceProvider`. See the [Base Installation Guide](https://socialiteproviders.com/usage/) for detailed instructions. + +```php +protected $listen = [ + \SocialiteProviders\Manager\SocialiteWasCalled::class => [ + // ... other providers + \SocialiteProviders\Clover\CloverExtendSocialite::class.'@handle', + ], +]; +``` + +### Usage + +You should now be able to use the provider like you would regularly use Socialite (assuming you have the facade installed): + +```php +return Socialite::driver('clover')->redirect(); +``` + +Presumably you are using this OAuth provider in order to retrieve an API token for calling other API endpoints. + +The user includes a `token` property that you can use to retrieve the API token like this: + +```php +Route::get('clover/auth/callback', function () { + $user = Socialite::driver('clover')->user(); + + // Save these tokens somewhere for use with the API. + $token = $user->accessTokenResponseBody; + + // Here’s what it looks like: + // [ + // 'access_token' => 'JWT', + // 'access_token_expiration' => 1709563149, + // 'refresh_token' => 'clvroar-6e49ffe9b5122f137aa39d8f7f930558', + // 'refresh_token_expiration' => 1741097349, + // ] + + // You may also want to store the merchant ID somewhere. + $merchantId = request()->input('merchant_id'); + + // Here’s what it looks like: + // 'ABC123DEF4567' +}); +``` diff --git a/src/Clover/composer.json b/src/Clover/composer.json new file mode 100644 index 000000000..ba5746806 --- /dev/null +++ b/src/Clover/composer.json @@ -0,0 +1,33 @@ +{ + "name": "socialiteproviders/clover", + "description": "Clover OAuth2 Provider for Laravel Socialite", + "license": "MIT", + "keywords": [ + "clover", + "laravel", + "oauth", + "provider", + "socialite" + ], + "authors": [ + { + "name": "macbookandrew", + "homepage": "https://andrewrminion.com" + } + ], + "support": { + "issues": "https://github.com/socialiteproviders/providers/issues", + "source": "https://github.com/socialiteproviders/providers", + "docs": "https://socialiteproviders.com/clover" + }, + "require": { + "php": "^8.1", + "ext-json": "*", + "socialiteproviders/manager": "^4.4" + }, + "autoload": { + "psr-4": { + "SocialiteProviders\\Clover\\": "" + } + } +}