question

Alex Schittko avatar image
Alex Schittko asked ·

OAU-213 Token not found, token is failing to refresh

I'm having an issue building out my first RingCentral app. Using PHP 7 with the RingCentral PHP SDK fetched via Composer.

The idea here is the app will need to be authorized once upon startup, and will stay logged in as long as the app is running, allowing any user who queries the app to achieve a result from RingCentral, parsed in a manner acceptable for my org.

When the app goes through the oauth2 login flow, upon success it will store the access token to a cache (Redis):


if (isset($_REQUEST['oauth2callback'])){
 if (!isset($_GET['code'])) {
 return;
 }
 $qs = $platform->parseAuthRedirectUrl($_SERVER['QUERY_STRING']);
 $qs["redirectUri"] = $RINGCENTRAL_REDIRECT_URL;

 $platform->login($qs);
 $_SESSION['sessionAccessToken'] = $platform->auth()->data();
 
 $redis->set("accessToken", serialize($_SESSION['sessionAccessToken']));


On every subsequent page load that requires the app to be authenticated with RingCentral, we check if the token exists, and set it on the platform object if appropriate. Else, we'll redirect to the login flow.

$rcsdk = new SDK($RINGCENTRAL_CLIENT_ID, $RINGCENTRAL_CLIENT_SECRET, $RINGCENTRAL_SERVER_URL);
$platform = $rcsdk->platform();

if (! $redis->get("accessToken")) { 
 header("Location: " . $host);
}
else {
 session_start();
 $_SESSION['sessionAccessToken'] = $redis->get('accessToken');
 $platform->auth()->setData( unserialize( $_SESSION['sessionAccessToken'] ) );
}


Based on the README for the php SDK, the platform object is capable of refreshing the token itself in the event that the access token expires.


The app has a component where it runs a cron job periodically to seed it's database with fresh data from the RC API:

<?php

// Log in to the API
require(__DIR__ . '/vendor/autoload.php');
require_once("./config/configs.php");
require_once("./database/redis.php");

use RingCentral\SDK\Http\HttpException;
use RingCentral\SDK\Http\ApiResponse;
use RingCentral\SDK\SDK;

$rcsdk = new SDK($RINGCENTRAL_CLIENT_ID, $RINGCENTRAL_CLIENT_SECRET, $RINGCENTRAL_SERVER_URL);
$platform = $rcsdk->platform();

if (! $redis->get("accessToken")) { 
 die("Cron is exiting because the app is not logged in");
}

// Get the call records
$platform->auth()->setData( unserialize( $redis->get("accessToken") ) );
try { 
 $apiResponse = $rcsdk->platform()->get('/restapi/v1.0/account/~/active-calls', array( "Direction" => "Inbound", "view" => "Detailed")) ;
}
catch (\RingCentral\SDK\Http\ApiException $e) {
 // Getting error messages using PHP native interface
 print 'RC API Error: ' . $e->getMessage() . PHP_EOL;
 die();
}
// Store to DB
$redis->set("callLog", serialize($apiResponse->json()->records));

echo "Refreshed the call data!";
?>


After about an hour of leaving the application running, the cron starts dieing out on:

RC API Error: Token not found

I was able to dump the request and response objects when I get a Token not found error:

Expected HTTP Error: Token not found
GuzzleHttp\Psr7\Request Object
(
[method:GuzzleHttp\Psr7\Request:private] => POST
[requestTarget:GuzzleHttp\Psr7\Request:private] =>
[uri:GuzzleHttp\Psr7\Request:private] => GuzzleHttp\Psr7\Uri Object
(
[scheme:GuzzleHttp\Psr7\Uri:private] => https
[userInfo:GuzzleHttp\Psr7\Uri:private] =>
[host:GuzzleHttp\Psr7\Uri:private] => platform.ringcentral.com
[port:GuzzleHttp\Psr7\Uri:private] =>
[path:GuzzleHttp\Psr7\Uri:private] => /restapi/oauth/token
[query:GuzzleHttp\Psr7\Uri:private] =>
[fragment:GuzzleHttp\Psr7\Uri:private] =>
)

[headers:GuzzleHttp\Psr7\Request:private] => Array
(
[Host] => Array
(
[0] => platform.ringcentral.com
)

[Authorization] => Array
(
[0] => Basic <I TRUNCATED THE KEY FROM THIS OUTPUT>
)

[Content-Type] => Array
(
[0] => application/x-www-form-urlencoded
)

[accept] => Array
(
[0] => application/json
)

[User-Agent] => Array
(
[0] => Unnamed/0.0.0 Linux/4.4.0-18362-Microsoft PHP/7.2.24-0ubuntu0.18.04.6 RCPHPSDK/2.2.3
)

[RC-User-Agent] => Array
(
[0] => Unnamed/0.0.0 Linux/4.4.0-18362-Microsoft PHP/7.2.24-0ubuntu0.18.04.6 RCPHPSDK/2.2.3
)

)

[headerNames:GuzzleHttp\Psr7\Request:private] => Array
(
[authorization] => Authorization
[content-type] => Content-Type
[accept] => accept
[user-agent] => User-Agent
[rc-user-agent] => RC-User-Agent
[host] => Host
)

[protocol:GuzzleHttp\Psr7\Request:private] => 1.1
[stream:GuzzleHttp\Psr7\Request:private] => GuzzleHttp\Psr7\Stream Object
(
[stream:GuzzleHttp\Psr7\Stream:private] => Resource id #68
[size:GuzzleHttp\Psr7\Stream:private] => 408
[seekable:GuzzleHttp\Psr7\Stream:private] => 1
[readable:GuzzleHttp\Psr7\Stream:private] => 1
[writable:GuzzleHttp\Psr7\Stream:private] => 1
[uri:GuzzleHttp\Psr7\Stream:private] => php://temp
[customMetadata:GuzzleHttp\Psr7\Stream:private] => Array
(
)

)

)
GuzzleHttp\Psr7\Response Object
(
[reasonPhrase:GuzzleHttp\Psr7\Response:private] => Bad Request
[statusCode:GuzzleHttp\Psr7\Response:private] => 400
[headers:GuzzleHttp\Psr7\Response:private] => Array
(
[Server] => Array
(
[0] => nginx
)

[Date] => Array
(
[0] => Wed, 15 Jul 2020 23:08:13 GMT
)

[Content-Type] => Array
(
[0] => application/json;charset=utf-8
)

[Content-Length] => Array
(
[0] => 161
)

[Connection] => Array
(
[0] => keep-alive
)

[X-Application-Context] => Array
(
[0] => application:8080
)

[Content-Language] => Array
(
[0] => en
)

[RCRequestId] => Array
(
[0] => 0edf196e-c6f0-11ea-8fa3-005056af98c7
)

[Pragma] => Array
(
[0] => no-cache
)

[Cache-Control] => Array
(
[0] => no-store
)

[AceRoutingKey] => Array
(
[0] => iad41-c01-ace02.4d0d56f5-b9cf-11ea-afde-0050568d0f78
)

[RoutingKey] => Array
(
[0] => SJC01P06
)

)

[headerNames:GuzzleHttp\Psr7\Response:private] => Array
(
[server] => Server
[date] => Date
[content-type] => Content-Type
[content-length] => Content-Length
[connection] => Connection
[x-application-context] => X-Application-Context
[content-language] => Content-Language
[rcrequestid] => RCRequestId
[pragma] => Pragma
[cache-control] => Cache-Control
[aceroutingkey] => AceRoutingKey
[routingkey] => RoutingKey
)

[protocol:GuzzleHttp\Psr7\Response:private] => 1.1
[stream:GuzzleHttp\Psr7\Response:private] => GuzzleHttp\Psr7\Stream Object
(
[stream:GuzzleHttp\Psr7\Stream:private] => Resource id #76
[size:GuzzleHttp\Psr7\Stream:private] =>
[seekable:GuzzleHttp\Psr7\Stream:private] => 1
[readable:GuzzleHttp\Psr7\Stream:private] => 1
[writable:GuzzleHttp\Psr7\Stream:private] => 1
[uri:GuzzleHttp\Psr7\Stream:private] => php://temp
[customMetadata:GuzzleHttp\Psr7\Stream:private] => Array
(
)

)

)


So, clearly, the token refreshing is either
a) not happening
b) happening in a context that doesn't push the token back up to my client

Can I be provided with some sample code to manually refresh the token?
Or guidance on storing the refreshed token so that the app will function?
Seeing as I already run cron jobs to seed data, adding another (check if token is refreshed ? do token refresh) block of code will be trivial at this point.

Many thanks!

oauth2php
1594858889394.png (133.9 KiB)
1 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Alex Schittko avatar image
Alex Schittko answered ·

Yeah, that was the solution. I needed to store the token at the end of every cron run, so that in the event that the platform refreshed the token, I will be storing the new token.

Share
1 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Alex Schittko avatar image
Alex Schittko answered ·

Aha! I think I might be on to something

Just because the platform is capable of refreshing the token, doesn't mean I'm storing the refreshed token.


A few lines of code to the cron job before we start calling the API for active calls:

// Get the call records
$platform->auth()->setData( unserialize( $redis->get("accessToken") ) );
if ( ! $platform->loggedIn() ) {
    $platform->refresh();
    error_log("I refreshed my own token!");
}

try { 
    $apiResponse = $rcsdk->platform()->get('/restapi/v1.0/account/~/active-calls', array( "Direction" => "Inbound", "view" => "Detailed")) ;
}

And an extra line to the end, when stuff gets stored to the cache:

// Store to DB
$redis->set("callLog", serialize($apiResponse->json()->records));

// Store the token object back to cache.
// The token object will refresh if needed.
// If the token was refreshed, we will need to store the new one, like this.
$redis->set("accessToken", serialize($platform->auth()->data()));

I'm going to let this cron job run overnight and see if this works the way it's intended now

Share
1 |1000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 10 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.