reddit-php-sdk
reddit-php-sdk copied to clipboard
Application Only OAuth
I have a script that posts a story to one of my subreddits. At some point this script should be launched via a cronjob.
This is where I'm stuck: my script works inside a user context, but not without manual authorization, which is necessary for the cron workflow.
I've read this page on the reddit API wiki, but do not understand how to make it work using the php SDK.
This 2-legged OAuth scenario is not currently supported in the SDK. After looking through the requirements for getting this working, this should just require some alterations to the constructor to pass through a different grant_type (and a device id) in the initial request. That should produce back the access token needed. All user centric methods would still be available in the SDK, but they would fail with a 403 back from Reddit servers. This would probably be the easiest way of getting it working. Let me take a look once I can.
All user centric methods would still be available in the SDK, but they would fail with a 403 back from Reddit servers.
So you mean that even if it worked, the API would not allow to write the story to the subreddit ?
Thank you very much for your follow up.
Any updates on getting this working?
There are many third-party apps that allow the user to post without authenticating every time so this must be possible.
I added the following. I had to create a prime.php page to auth and pull the initial access and refresh tokens but after that everything works.
To use permanent tokens you store the access token and refresh token somewhere. Then you make calls with the access token until it expires, when it expires you re auth but with refresh token and then update. Refresh token is not updated.
NOTE: duration=permanent and I tried my best to obfiscate my implementation and leave the needed info.
wtformatting...
public function __construct($db){
$this->db = $db;
$this->redirect = false;
if (isset($_GET['code']))
{
$this->getNewAccessToken($_GET["code"]);
}
else
{
$sql = "SELECT token_type,access_token,refresh_token,expire_time FROM TABLE WHERE id = 'CONTORLID' AND access_token != '';";
//access_token != '' is for priming when broken
//You need to have this a row for controlid already in the DB, this will not add.
$res = $this->db->query($sql);
if ($row = $res->fetch_assoc())
{
if($row['expire_time']<date("YmdHis"))
{
$this->refreshTokens($row['refresh_token']);
}
else
{
$this->access_token = $row['access_token'];
$this->token_type = $row['token_type'];
}
}
else
{
$state = rand();
$urlAuth = sprintf("%s?response_type=code&client_id=%s&redirect_uri=%s&scope=%s&state=%s&duration=permanent",
redditConfig::$ENDPOINT_OAUTH_AUTHORIZE,
redditConfig::$CLIENT_ID,
redditConfig::$ENDPOINT_OAUTH_REDIRECT,
redditConfig::$SCOPES,
$state);
//forward user to auth page
//Framework handles redirect otherwise use header
$this->redirect = "$urlAuth";
}
}
//set API endpoint
$this->apiHost = redditConfig::$ENDPOINT_OAUTH;
//set auth mode for requests
$this->auth_mode = 'oauth';
}
private function getNewAccessToken($code)
{
//construct POST object for access token fetch request
$postvals = sprintf("code=%s&redirect_uri=%s&grant_type=authorization_code",
$code,
redditConfig::$ENDPOINT_OAUTH_REDIRECT);
//get JSON access token object (with refresh_token parameter)
$token = self::runCurl(redditConfig::$ENDPOINT_OAUTH_TOKEN, $postvals, null, true);
//store token and type
if (isset($token['access_token']))
{
$this->saveToken($token);
}
else
{
var_dump($token);
}
}
private function refreshTokens($rfToken)
{
//construct POST object for access token fetch request
$postvals = sprintf("refresh_token=%s&redirect_uri=%s&grant_type=refresh_token",
$rfToken,
redditConfig::$ENDPOINT_OAUTH_REDIRECT);
//get JSON access token object (with refresh_token parameter)
$token = self::runCurl(redditConfig::$ENDPOINT_OAUTH_TOKEN, $postvals, null, true);
//store token and type
if (isset($token['access_token']))
{
$this->saveToken($token);
}
else
{
var_dump($token);
}
}
private function saveToken($token)
{
$this->access_token = $token['access_token'];
$this->token_type = $token['token_type'];
$dt = new DateTime();
$dt = $dt->add(new DateInterval("PT".$token['expires_in']."S"));
$expires = $dt->format("YmdHis");
if (isset($token['refresh_token']))
{
$upd = "UPDATE TABLE SET token_type=?,access_token=?,refresh_token=?,expire_time=? WHERE id='CONTROLID';";
if ($stmt = $this->db->prepare($upd))
{
$type = $token['token_type'];
$access = $token['access_token'];
$refrsh = $token['refresh_token'];
$stmt->bind_param('ssss',$type,$access,$refrsh,$expires);
$stmt->execute();
$stmt->close();
}
}
else
{
$upd = "UPDATE TABLE SET token_type=?,access_token=?,expire_time=? WHERE id='CONTROLID';";
if ($stmt = $this->db->prepare($upd))
{
$type = $token['token_type'];
$access = $token['access_token'];
$stmt->bind_param('sss',$type,$access,$expires);
$stmt->execute();
$stmt->close();
}
}
}
``
`