Grynets Grynets - 7 months ago 115
PHP Question

How to renew access token with OAuth Refresh token?

I'm creating simple app for Uber.

And I've already solved 3 steps from this API: https://developer.uber.com/docs/authentication

But now I want to refresh token (step 5).

I receive access_token, refresh_token, expires_in values, and I can't understand how to set up timer to refresh user's token with refresh_token when the expires_in time expire.

Here I provide my example of code, where I want to renew access token with refresh_token.


<?php
session_start();

require_once 'uber_b.php';
require_once 'config.php';


if(isset($_GET['code'])) {
// try to get an access token
$code = $_GET['code'];
$url = 'https://login.uber.com/oauth/token';

/*
* Create row for function setPostData (uber_b.php)
* All of this rows will be used to build our request
*/
$params = array(
"code" => $code,
"client_id" => $client_id,
"client_secret" => $client_secret,
"redirect_uri" => $redirect,
"grant_type" => "authorization_code"
);
//create example of class
$request = new HttpPost($url);
//Connect this class with our settings
$request->setPostData($params);
//Send our request to Uber
$request->send();
//Receive response
$responseObj = json_decode($request->getHttpResponse());
//Execute parameters from answer
$user_token = $responseObj->access_token;
//Refresh token
$refresh_token = $responseObj->refresh_token;
//Time for token
$expires_in = $responseObj->expires_in;

echo "User's token: " . $user_token;
echo "<br>";
echo "Refresh token is: " .$refresh_token ;
echo "<br>";
echo "Time: ".$expires_in;
echo "<br>";
echo "<a href='order.php'>Order a car</a>";
}

//Refresh token
if(isset($responseObj))
{
$exp_time = time()+2592000;
try {
//insert into database
$stmt = $db->prepare('INSERT INTO token2 (exp_time)
VALUES (:exp_time)
');
$stmt->execute(array(
':exp_time' => $exp_time
));
} catch(PDOException $e) {
echo $e->getMessage();
}
}
if(time() >= $exp_time)
{
//Parameters for Uber refresh token request(step 5)
$r_params = array(
"client_id" => $client_id,
"client_secret" => $client_secret,
"redirect_uri" => $redirect,
"grant_type" => "refresh_token",
"refresh_token" => $refresh_token
);
$r_request = new RefreshToken($url);

$r_request->setPostData($r_params);
$r_request->send();
$refresh = $refresh_token;
$r_responseObj = json_decode($r_request->Refresh());

echo "New Refresh token: " . $r_responseObj->refresh_token;
echo "<br>";
}
?>


As you see, I don't provide timer function, because I don't understand how to make it right.

So, can you explain me how to correctly renew access_token using refresh_token?

Maybe I have to use setcookie(), or something else to solve this task?

Answer
  • First of all, according to the STEP FIVE: REFRESHING TOKENS from the Authentication docs, to refresh the access token you need to HTTP POST the following parameters:

    client_secret=YOUR_CLIENT_SECRET
    client_id=YOUR_CLIENT_ID
    grant_type=refresh_token
    redirect_uri=YOUR_REDIRECT_URI
    refresh_token=REFRESH_TOKEN

    to the https://login.uber.com/oauth/v2/token API endpoint

    You are also sending the code parameter, which means you will receive an error because of this additional parameter which fails to validate on Uber's server. The error you get will be

    HTTP/1.1 401 UNAUTHORIZED
    {"error": "invalid_grant"}  
    
  • To be able to check the token validity, after you've exchanged the code with the access token, you need to:

    • Persist somewhere the "access_token", "expires_in", "refresh_token" and a UNIX timestamp in seconds, representing the current time and date, let's call it "itime".

    • The location where you can store this information is multi varied: session, file, database, memory cache, etc., depending on how you want to handle token expiration and automatic user login if you already have their token saved and it's not expired, then you don't have to make the user login again.

    • Before each HTTP request that you make to the Uber API you first check that the access token hasn't expired by retrieving the "itime" and "expires_in" from the storage location for the access token of the user and making sure that the time() < "itime"+"expires_in" holds true.
      If the condition is false, then you need to refresh the access token.

    • Keep in mind that refreshing the access token also changes the refresh token, so you need to replace the current "access_token", "refresh_token" and "expires_in" for the current user identified by the uuid.

    • Given that the current expiration time for an access token is 30 days (2592000 seconds) I'd suggest that you store the access token data inside a database table, because PHP sessions are short lived (by default session.gc_maxlifetime is 1440 seconds/24 minutes in php.ini) and the user will not stay on your app/website all that time either.
    • Moreover, checking the expiration time is not enough if you allow the user to login to Uber from multiple devices/places, because after each user login all the previous access/refresh tokens are invalidated. So, after the user signs in on the second device you might have an invalid access/token with a valid expiration time on the first device. In this scenario, to determine if the access token is still valid I'd suggest you make an additional HTTP request to the GET /v1/me endpoint using the access token. If it works, the token is still valid, otherwise it expired/was invalidated, and you need to request a user re-login on the first device.

tl;dr You don't need a timer, you need to check before each HTTP request to the Uber API that the access token is still valid.
To do this, you need to persist the token details + UNIX timestamp.