Skip to content

Instantly share code, notes, and snippets.

@ralphschindler
Created November 26, 2014 16:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ralphschindler/a585cd74973a97ffee3f to your computer and use it in GitHub Desktop.
Save ralphschindler/a585cd74973a97ffee3f to your computer and use it in GitHub Desktop.
A Barebones OAuth2 PHP Client demonstrating the "Password Grant Type"
<?php
namespace SampleOauth2Client;
class Client
{
protected $configuration = [
'token_file' => null, // path to a file to store token information
'api_authorization_token' => null, // authorization to talk to token service
'api_token_url' => null, // url to post to
'api_username' => null, // username
'api_password' => null, // password
'api_scope' => null, // scope to request access for
];
public function __construct($configuration)
{
$this->configuration = $configuration;
}
public function getAccessToken($refresh = false)
{
if (!isset($this->configuration['token_file'])) {
throw new \RuntimeException(__CLASS__ . ' requires a file to store access token information in');
}
$tokenDataFile = $this->configuration['token_file'];
$tokenData = unserialize(file_get_contents($tokenDataFile));
$tokenIsExpired = (time() > $tokenData['access']['expiration']);
if (!$tokenData || $refresh || $tokenIsExpired) {
$this->refreshTokens();
}
$tokenData = unserialize(file_get_contents($tokenDataFile));
return $tokenData['access']['token'];
}
protected function refreshTokens()
{
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Authorization: Basic {$this->configuration['api_authorization_token']}\r\n"
. "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => "grant_type=password&username={$this->configuration['api_username']}"
. "&password={$this->configuration['api_password']}"
. "&scope={$this->configuration['api_scope']}",
]
]);
$content = file_get_contents($this->configuration['api_token_url'], null, $context);
if (!strpos($http_response_header[0], '200 OK')) {
throw new \RuntimeException('Could not obtain an access token');
}
$decoded = json_decode($content, true);
$tokenData = [
'access' => [
'token' => $decoded['access_token'],
'expiration' => (time() + $decoded['expires_in'])
],
'refresh' => [
'token' => $decoded['refresh_token']
]
];
file_put_contents($this->configuration['token_file'], serialize($tokenData));
}
}
@philsturgeon
Copy link

Yep, so this is a difference in goals.

When you build your own OAuth 2 server, you can interact with it SO easily it hurts, just by throwing a few values at it via HTTP requests.

You are very well versed with the OAuth 2 spec, and that's all gravy, but most providers are either not versed with the spec, or flagrantly ignore it.

Some providers run their token endpoints on GET or POST for instance, which is nutty. Providers help with that.

This package was always aimed to get people working with the popular providers way before worrying about those making their own servers, because this code existed in some form (my old CodeIgniter-OAuth2 package) before either Brett or Alex had built their OAuth 2 servers, and before it seemed reasonable that people would be doing that so often as they are now.

ANYHOO, making it work without having to make your own provider certainly seems like a great goal and me and Ben are both A++ on that. Your #1 is taken care of.

2.) Probably not. We did that for OAuth 2.0 Server and it was just a mess. People want PDO wrappers and Memcache drivers and Eloquent ORM drivers and oh god just do it yourself. :)

3.) I'm gonna go with a big nope on swappable HTTP Clients, as the FIG might be able to make that much easier for us in the future. I regularly use Geocoder as a perfect example of why the FIG needs to keep fighting its fight, and HTTP Message is getting close enough to make a lot of this stuff much easier.

Guzzle is pretty much a defacto standard recently, and although some like streams Guzzle can use streams now too - not that it would make much difference to anyone WHAT its doing under the hood.

So a big yes to 1, nope on 2 and soon on 3. :)

@ralphschindler
Copy link
Author

Different goals, that's fair enough.

  1. How about refreshing access tokens automatically after they are expired when you know the service to be implementing the refresh token grant type (instead of pushing that workflow onto the consumer)?

Guzzle, meh! After months away from zf2 development, I forget about the religious sect FIG in php that believes in the one-true-interface ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment