145 lines
4.1 KiB
PHP
145 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Intuit\Providers\Socialite;
|
|
|
|
use Carbon\Carbon;
|
|
use GuzzleHttp\RequestOptions;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Laravel\Passport\Exceptions\InvalidAuthTokenException;
|
|
use Laravel\Socialite\Two\InvalidStateException;
|
|
use Laravel\Socialite\Two\ProviderInterface;
|
|
use Laravel\Socialite\Two\AbstractProvider;
|
|
use Laravel\Socialite\Two\User as SocialUser;
|
|
|
|
use App\Models\{ProviderOauth,ProviderToken};
|
|
|
|
class IntuitProvider extends AbstractProvider implements ProviderInterface
|
|
{
|
|
private const LOGKEY = 'SIP';
|
|
|
|
private const hosts = [
|
|
'authorise' => 'https://appcenter.intuit.com/connect/oauth2',
|
|
'tokenendpoint' => 'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
|
|
'local' => 'https://sandbox-quickbooks.api.intuit.com',
|
|
'production' => 'https://quickbooks.api.intuit.com',
|
|
];
|
|
protected $scopes = ['com.intuit.quickbooks.accounting'];
|
|
|
|
/* ABSTRACT */
|
|
|
|
protected function getAuthUrl($state)
|
|
{
|
|
return $this->buildAuthUrlFromBase(
|
|
Arr::get(self::hosts,'authorise'),
|
|
$state
|
|
);
|
|
}
|
|
|
|
protected function getUserByToken($token)
|
|
{
|
|
$response = [];
|
|
|
|
$access = $this->getAccessTokenResponse($token);
|
|
|
|
if ((! $x=Arr::get($access,'token_type')) || ($x !== 'bearer')) {
|
|
$response['reject'] = TRUE;
|
|
$response['reject_reason'] = 'No bearer token?';
|
|
|
|
return $response;
|
|
}
|
|
|
|
return $response ?: $access;
|
|
}
|
|
|
|
protected function getTokenUrl()
|
|
{
|
|
return Arr::get(self::hosts,'tokenendpoint');
|
|
}
|
|
|
|
protected function mapUserToObject(array $user)
|
|
{
|
|
return (new SocialUser)->setRaw(Auth::user()->toArray());
|
|
}
|
|
|
|
/* OVERRIDES */
|
|
|
|
public function user()
|
|
{
|
|
if ($this->hasInvalidState()) {
|
|
throw new InvalidStateException;
|
|
}
|
|
|
|
if (! $this->getCode())
|
|
return NULL;
|
|
|
|
$details = $this->getUserByToken($this->getCode());
|
|
|
|
if ((! $details) || Arr::get($details,'reject'))
|
|
abort(403, sprintf('Authentication Failed with %s',Arr::get($details,'reject_reason','*no reason given*')));
|
|
|
|
$user = $this->mapUserToObject($details);
|
|
$user->refresh_token_expires_in = Arr::get($details,'x_refresh_token_expires_in');
|
|
$user->realmid = $this->request->get('realmId');
|
|
|
|
return $user->setToken(Arr::get($details,'access_token'))
|
|
->setRefreshToken(Arr::get($details,'refresh_token'))
|
|
->setExpiresIn(Arr::get($details,'expires_in'));
|
|
}
|
|
|
|
/* METHODS */
|
|
|
|
public function getAuthorisationHeader(ProviderOauth $po): array
|
|
{
|
|
return [
|
|
'Accept' => 'application/json',
|
|
'Authorization' => sprintf('Basic %s',base64_encode($this->clientId.':'.$this->clientSecret)),
|
|
'Content-Type' => 'application/x-www-form-urlencoded'
|
|
];
|
|
}
|
|
|
|
public function getRefreshTokenFields(string $refreshtoken): array
|
|
{
|
|
return [
|
|
'grant_type' => 'refresh_token',
|
|
'refresh_token' => $refreshtoken,
|
|
];
|
|
}
|
|
|
|
public function refreshToken($to)
|
|
{
|
|
Log::debug(sprintf('%s:= Refreshing token for [%d]',self::LOGKEY,$to->id));
|
|
|
|
$response = $this
|
|
->getHttpClient()
|
|
->post($this->getTokenUrl(),[
|
|
RequestOptions::HEADERS => $this->getAuthorisationHeader($to->provider),
|
|
RequestOptions::FORM_PARAMS => $this->getRefreshTokenFields($to->refresh_token),
|
|
]);
|
|
|
|
switch ($response->getStatusCode()) {
|
|
case '200':
|
|
$body = json_decode($response->getBody(), true);
|
|
|
|
if (Arr::get($body,'token_type') !== 'bearer')
|
|
throw new InvalidAuthTokenException(sprintf('Invalid response [%d] didnt get a bearer token for [%s] (%s)',$response->getStatusCode(),$to->user->email,$body));
|
|
|
|
$to->access_token = Arr::get($body,'access_token');
|
|
$to->access_token_expires_at = Carbon::now()->addSeconds(Arr::get($body,'expires_in'));
|
|
|
|
// If the refresh token changed
|
|
if (($x=Arr::get($body,'refresh_token')) !== $to->refresh_token) {
|
|
$to->refresh_token = $x;
|
|
$to->refresh_token_expires_at = Carbon::now()->addSeconds(Arr::get($body,'x_refresh_token_expires_in'));
|
|
|
|
Log::debug(sprintf('%s:= Refresh token updated.',self::LOGKEY));
|
|
}
|
|
|
|
return $to->save();
|
|
|
|
default:
|
|
throw new InvalidAuthTokenException(sprintf('Invalid response [%d] refreshing token for [%s] (%s)',$response->getStatusCode(),$to->user->email,$response->getBody()));
|
|
}
|
|
}
|
|
} |