Implementing Twitter sign-in with Silex and PHP
Set-up
- Install pecl oauth
- Grab the Silex
.phararchive - Create a Twitter application
pecl oauth
Install the pecl oauth extension
For example:
$ pecl install oauth
Silex
For those not acquainted with Silex:
Silex is a PHP microframework for PHP 5.3
A microframework provides the guts for building simple single-file apps.
It's awesome.
All you need is the silex.phar file and you're away. Download it.
For the example, I've setup a virtual host of example.local on my development machine. The apache module mod_rewrite and a .htaccess file are used to rewrite requests to index.php.
# .htaccess
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
#RewriteBase /path/to/app
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
Create a Twitter application
Once you've created your application, you'll need your consumer key and consumer secret. These are used to sign every request made to the API.
Implementation
A complete summary along with a pretty diagram of what we're trying to achieve can be found here.
Basic OAuth request cycle:
- Retrieve a request token
- Request authorization
- Exchange the request token for an access token
More information - https://dev.twitter.com/docs/auth/oauth
Basic Silex application
// index.php
define('CONS_KEY', 'Application consumer key');
define('CONS_SECRET', 'Application consumer secret');
require_once __DIR__.'/silex.phar';
$app = new Silex\Application();
// register the session extension
$app->register(new Silex\Extension\SessionExtension());
$app->get('/', function() use($app) {
$username = $app['session']->get('username');
if ($username == null) {
return 'Welcome Guest. <a href="/login">Login</a>';
} else {
return 'Welcome ' . $app->escape($username);
}
});
$app->run();
Add the /login route
The first part of the process requires the retrieval of a request token. Authorization is requested by redirecting to https://twitter.com/oauth/authenticate.
// index.php
$app->get('/login', function () use ($app) {
// check if the user is already logged-in
if (null !== ($username = $app['session']->get('username'))) {
return $app->redirect('/');
}
$oauth = new OAuth(CONS_KEY, CONS_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
$request_token = $oauth->getRequestToken('https://twitter.com/oauth/request_token');
$app['session']->set('secret', $request_token['oauth_token_secret']);
return $app->redirect('https://twitter.com/oauth/authenticate?oauth_token=' . $request_token['oauth_token']);
});
Add the /auth route
In my example setup the URL would be http://example.local/auth. Set your Twitter application callback URL in the app settings to be the auth route.
Within this action, the request token is exchanged with the access token which allows usage of the Twitter API on behalf of the user.
// index.php
$app->get('/auth', function() use ($app) {
// check if the user is already logged-in
if (null !== ($username = $app['session']->get('username'))) {
return $app->redirect('/');
}
$oauth_token = $app['request']->get('oauth_token');
if ($oauth_token == null) {
$app->abort(400, 'Invalid token');
}
$secret = $app['session']->get('secret');
$oauth = new OAuth(CONS_KEY, CONS_SECRET, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
$oauth->setToken($oauth_token, $secret);
try {
$oauth_token_info = $oauth->getAccessToken('https://twitter.com/oauth/access_token');
} catch (OAuthException $e) {
$app->abort(401, $e->getMessage());
}
// retrieve Twitter user details
$oauth->setToken($oauth_token_info['oauth_token'], $oauth_token_info['oauth_token_secret']);
$oauth->fetch('https://twitter.com/account/verify_credentials.json');
$json = json_decode($oauth->getLastResponse());
$app['session']->set('username', $json->screen_name);
return $app->redirect('/');
});
Resources
- Comments [4]
Is there something missing from the last code example? Your /auth controller's closure uses $pdo, but it isn't used to persist the oauth access token.
Good spot. I do use PDO to persist the oauth access token but removed it for the examples to reduce the amount of code. Have updated the gist and blog post.
Thanks, Ade (@Jeremy Mikola - nice catch too)! Great example... was looking for something similar but lighter yet from ninjauth... any of you got that incorp'd into the Silex as a package?
Bill
Hi Ade,
Many thanks for the tutorial.
I actually came here from google searching for examples on using PDO storage for Sliex sessions and I see you mention this in the comment above but have removed the original references!
I can't find any clear information on how to do this anywhere. Any guidance would be massively appreciated! Cheers