Skip to content

Commit f721c88

Browse files
authored
Merge pull request hybridauth#1255 from chrisgraham/instagram_token_exchange
Implemented Token Exchange for Instagram
2 parents 05d0a65 + 7c009ae commit f721c88

File tree

6 files changed

+92
-3
lines changed

6 files changed

+92
-3
lines changed

src/Adapter/AbstractAdapter.php

+8
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [
136136
throw new NotImplementedException('Provider does not support this feature.');
137137
}
138138

139+
/**
140+
* {@inheritdoc}
141+
*/
142+
public function maintainToken()
143+
{
144+
// Nothing needed for most providers
145+
}
146+
139147
/**
140148
* {@inheritdoc}
141149
*/

src/Adapter/AdapterInterface.php

+6
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ public function setPageStatus($status, $pageId);
9797
*/
9898
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false);
9999

100+
/**
101+
* Do whatever may be necessary to make sure tokens do not expire.
102+
* Intended to be be called frequently, e.g. via Cron.
103+
*/
104+
public function maintainToken();
105+
100106
/**
101107
* Return oauth access tokens.
102108
*

src/Adapter/OAuth1.php

+3
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,9 @@ protected function validateAccessTokenExchange($response)
544544
*/
545545
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
546546
{
547+
// refresh tokens if needed
548+
$this->maintainToken();
549+
547550
if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
548551
$url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
549552
}

src/Adapter/OAuth2.php

+1
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,7 @@ protected function validateRefreshAccessToken($response)
710710
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
711711
{
712712
// refresh tokens if needed
713+
$this->maintainToken();
713714
if ($this->hasAccessTokenExpired() === true) {
714715
$this->refreshAccessToken();
715716
}

src/Provider/Facebook.php

+5-3
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ protected function initialize()
9292
/**
9393
* {@inheritdoc}
9494
*/
95-
public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
95+
public function maintainToken()
9696
{
97+
if (!$this->isConnected()) {
98+
return;
99+
}
100+
97101
// Handle token exchange prior to the standard handler for an API request
98102
$exchange_by_expiry_days = $this->config->get('exchange_by_expiry_days') ?: 45;
99103
if ($exchange_by_expiry_days !== null) {
@@ -102,8 +106,6 @@ public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [
102106
$this->exchangeAccessToken();
103107
}
104108
}
105-
106-
return parent::apiRequest($url, $method, $parameters, $headers, $multipart);
107109
}
108110

109111
/**

src/Provider/Instagram.php

+69
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,75 @@ protected function initialize()
5555
$this->apiRequestParameters[$this->accessTokenName] = $accessToken;
5656
}
5757

58+
/**
59+
* {@inheritdoc}
60+
*/
61+
protected function validateAccessTokenExchange($response)
62+
{
63+
$collection = parent::validateAccessTokenExchange($response);
64+
65+
if (!$collection->exists('expires_in')) {
66+
// Instagram tokens always expire in an hour, but this is implicit not explicit
67+
68+
$expires_in = 60 * 60;
69+
70+
$expires_at = time() + $expires_in;
71+
72+
$this->storeData('expires_in', $expires_in);
73+
$this->storeData('expires_at', $expires_at);
74+
}
75+
76+
return $collection;
77+
}
78+
79+
/**
80+
* {@inheritdoc}
81+
*/
82+
public function maintainToken()
83+
{
84+
if (!$this->isConnected()) {
85+
return;
86+
}
87+
88+
// Handle token exchange prior to the standard handler for an API request
89+
$exchange_by_expiry_days = $this->config->get('exchange_by_expiry_days') ?: 45;
90+
if ($exchange_by_expiry_days !== null) {
91+
$projected_timestamp = time() + 60 * 60 * 24 * $exchange_by_expiry_days;
92+
if (!$this->hasAccessTokenExpired() && $this->hasAccessTokenExpired($projected_timestamp)) {
93+
$this->exchangeAccessToken();
94+
}
95+
}
96+
}
97+
98+
/**
99+
* Exchange the Access Token with one that expires further in the future.
100+
*
101+
* @return string Raw Provider API response
102+
* @throws \Hybridauth\Exception\HttpClientFailureException
103+
* @throws \Hybridauth\Exception\HttpRequestFailedException
104+
* @throws InvalidAccessTokenException
105+
*/
106+
public function exchangeAccessToken()
107+
{
108+
$exchangeTokenParameters = [
109+
'grant_type' => 'ig_exchange_token',
110+
'client_secret' => $this->clientSecret,
111+
'access_token' => $this->getStoredData('access_token'),
112+
];
113+
114+
$response = $this->httpClient->request(
115+
'https://graph.instagram.com/access_token',
116+
'GET',
117+
$exchangeTokenParameters
118+
);
119+
120+
$this->validateApiResponse('Unable to exchange the access token');
121+
122+
$this->validateAccessTokenExchange($response);
123+
124+
return $response;
125+
}
126+
58127
/**
59128
* {@inheritdoc}
60129
*/

0 commit comments

Comments
 (0)