Skip to content

Instantly share code, notes, and snippets.

@joeswann
Last active June 14, 2018 00:52
Show Gist options
  • Save joeswann/ca2ead84b983c6cd535a to your computer and use it in GitHub Desktop.
Save joeswann/ca2ead84b983c6cd535a to your computer and use it in GitHub Desktop.
[oauth2.php] Oauth 2 example
<?php
//install
$app->match('/install/{state}', function($state) use ($app) {
return json_encode($app['vend_oauth']->install($state));
});
$app->post('/wombat/add_order', function() use ($app) {
$oauth = $app['vend_oauth']->getOrCreateToken();
if(isset($oauth['token'])) {
$app['vend']->initAPI($oauth['token']);
$response = $app['vend']->wombatAddOrder($app['settings']);
return new Response(
json_encode($response),
200,
['Content-Type' => 'application/json']
);
} else {
return json_encode($oauth);
}
});
<?php
namespace JoeSwann;
class VendBase {
public function __construct(&$app, $settings = array()) {
$this->app = $app;
$this->settings = $settings;
$this->db = $this->app['db'];
$this->spree_api = new SpreeAPI($app, $settings);
$this->model = new VendModel($app, $settings);
}
public function initAPI($token) {
$url = 'https://' . $this->settings['oauth']['domain_prefix'] . '.vendhq.com';
$token_type = 'Bearer';
$access_token = $token['access_token'];
$this->vend_api = new \VendAPI\VendAPI($url,$token_type, $access_token);
$this->api = new VendAPI($this->app, $this->vend_api,$this->settings);
}
}
<?php
namespace JoeSwann;
class VendOauth extends VendBase {
function install($state) {
$session = &$this->app['session'];
//Unpack our saved parameters out of database for use with getProvider
$settings = $this->db->fetchAssoc('select * from install where state = ?', [$state]);
if($settings == false) die('no records found');
//Send settings to provider
$provider = $this->getProvider($settings);
$auth_url = $settings['auth_url'];
$state = $settings['state'];
// Add our provided state to session
$session->set('oauth2state', $state);
//Redirect
header('Location: '.$auth_url);
exit;
}
function getOrCreateToken($state = false) {
$session = &$this->app['session'];
$request = &$this->app['request'];
//if we are installing we won't have oauth details as part of request
if($state) {
//Unpack our saved parameters out of database for use with getProvider
$oauth = $this->db->fetchAssoc('select * from install where state = ? limit 1', [$state]);
if($oauth == false) die('no records found');
$domain_prefix = $oauth['domain_prefix'];
} else {
$oauth = $this->settings['oauth'];
$domain_prefix = $this->settings['oauth']['domain_prefix'];
}
//See if we already have a valid token
$token = $this->getToken($domain_prefix);
//If the token has expired then we should refresh it
if($token) {
// Check expiry
if($this->hasExpired($token)) {
//The latest token doesn't have refresh
$token = $this->db->fetchAssoc('select * from token where retailer = ? order by expires asc', [$domain_prefix]);
$token = $this->refreshToken($token, $oauth);
return [
'action' => 'refresh token',
'token' => $token
];
} else {
return [
'action' => 'existing token',
'token' => $token
];
}
} else {
//Go ahead and install fresh
$provider = $this->getProvider($oauth);
$session_state = $session->get('oauth2state', false);
$request_code = $request->get('code', false);
$request_state = $request->get('state');
// If we don't have an authorization code then we haven't installed yet
if ($request_code == false) {
// Generate a state and save it + settings to database
$auth_url = $provider->getAuthorizationUrl();
$state = $provider->state;
// save installation settings using state as identifier
$install = [];
foreach($oauth as $key => $setting) {
$install[$key] = $setting;
}
$install['state'] = $state;
$install['auth_url'] = $auth_url;
$this->db->insert('install', $install);
return [
'action' => 'install application',
'auth_url' => "http://{$_SERVER[HTTP_HOST]}/install/{$state}"
];
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($session_state) || $session_state !== $request_state) {
$session->remove('oauth2state');
return [
'action' => 'reject state'
];
} else {
// Try to get an access token (using the authorization code grant)
$token_data = $provider->getAccessToken('authorization_code', [
'code' => $request_code
]);
$token = $this->saveToken($token_data, $oauth);
return [
'action' => 'save token',
'token' => $token
];
}
}
}
function refreshToken($token_data, $oauth) {
$grant = new \League\OAuth2\Client\Grant\RefreshToken();
$provider = $this->getProvider($oauth);
$token_data = $provider->getAccessToken($grant, ['refresh_token' => $token_data['refresh_token']]);
$token = $this->saveToken($token_data, $oauth);
return $token;
}
function hasExpired($token) {
//Compare current time against tokens expiry date - an hour (to avoid complications)
//hopefully requesting a new token before expiry isn't complicated
return (int)$token['expires'] < time();
}
function getToken($domain_prefix) {
//Just return the latest token assigned to the current retailer
$token = $this->db->fetchAssoc('select * from token where retailer = ? ORDER BY expires DESC', [$domain_prefix]);
return $token;
}
function saveToken($access_token,$oauth) {
//Is this a refresh token?
$retailer = $oauth['domain_prefix'];
$has_refresh = isset($access_token->refreshToken);
$token = [];
$token['retailer'] = $retailer;
$token['access_token'] = $access_token->accessToken;
$token['expires'] = $access_token->expires;
$token['has_refresh'] = $has_refresh;
if($has_refresh) {
$token['refresh_token'] = $access_token->refreshToken;
}
$this->db->insert('token', $token);
return $token;
}
function getProvider($oauth) {
return new \Wheniwork\OAuth2\Client\Provider\Vend([
'clientId' => $oauth['client_id'],
'clientSecret' => $oauth['client_secret'],
'domainPrefix' => $oauth['domain_prefix'],
'redirectUri' => $oauth['redirect_uri']
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment