I’ve working in a pet-project with Silex and I wanted to perform a Sign-in with Twitter. Implementing Sign in with Twitter is pretty straightforward and it’s also well explained in the Twitter’s developers site. Now we only need to implement those HTTP client requests within PHP. We can create the REST client with curl but nowadays I prefer to use the great library called Guzzle to perform those kind of opperations. So let’s start.
The idea is to create something reusable. I don’t want to spend too much time including the Sign-in with Twitter in my proyects, so my first idea was to create a class with all the needed code and mount this class as group of Silex controllers (as it’s defined here). I also want to keep the class as standard as possible and avoiding the usage of any other external dependencies (except Guzzle)..
Imagine a simple Silex application:
<?php // www/index.php include __DIR__ . "/../vendor/autoload.php"; $app = new Silex\Application(); $app->get('/', function () { return 'Hello'; }); $app->run();
Now I want to use a Sign-in with Twitter, so I will change the application to:
<?php include __DIR__ . "/../vendor/autoload.php"; $app = new Silex\Application(); $app->register(new Silex\Provider\SessionServiceProvider()); $consumerKey = "***"; $consumerSecret = "***"; $twitterLoggin = new SilexTwitterLogin($app, 'twitter'); $twitterLoggin->setConsumerKey($consumerKey); $twitterLoggin->setConsumerSecret($consumerSecret); $twitterLoggin->registerOnLoggin(function () use ($app, $twitterLoggin) { $app['session']->set($twitterLoggin->getSessionId(), [ 'user_id' => $twitterLoggin->getUserId(), 'screen_name' => $twitterLoggin->getScreenName(), 'oauth_token' => $twitterLoggin->getOauthToken(), 'oauth_token_secret' => $twitterLoggin->getOauthTokenSecret() ]); }); $twitterLoggin->mountOn('/login', function () { return '<a href="/login/requestToken">login</a>'; }); $app->get('/', function () use ($app){ return 'Hello ' . $app['session']->get('twitter')['screen_name']; }); $app->run();
The application will redirects all requests (without the correct session) to the route “/login”. The login page has a simple link to the route: “/login/requestToken” (we can create a fancy template with Twig if we want, indeed). This route redirects the request to Twitter’s login page and after a successful login it will redirects back to the route that we have defined within our Twitter application. The library assumes that this callback’s url is “/login/callbackUrl”. All this default routes can be defined by the user using the proper setters of the class.
When the sign-in is finished the application will trigger the callback defined in registerOnLoggin function and will redirects to the route “/”. This route (called internally “redirectOnSuccess”) is also customizable with a setter.
And that’s all. Library available at github and packagist
{ "require": { "gonzalo123/silex-twitter-login": "dev-master" } }
Hi, i’m using this piece of code in my Silex-application. The redirect to the twitter form is working ok. However, when coming back from twitter i get this error:
“Client error response [status code] 401 [reason phrase] Unauthorized [url] https://api.twitter.com/oauth/access_token”
How can this be solved?
Ensure that you are using the latest version from github. this issue is solved.
i’m using the dev-master version using composer. I’m still getting the error. Will continue to investigate…
still can’t get it to work… I’m using the dev-master version of guzzle.
The entire error message is:
Whoops, looks like something went wrong.
1/1ClientErrorResponseException: Client error response
[status code] 401
[reason phrase] Unauthorized
[url] https://api.twitter.com/oauth/access_token
in //vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php line 46
at BadResponseException::factory(object(EntityEnclosingRequest), object(Response)) in //vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php line 190
at Request::onRequestError(object(Event))
at call_user_func(array(‘Guzzle\Http\Message\Request’, ‘onRequestError’), object(Event)) in //vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php line 164
at EventDispatcher->doDispatch(array(array(‘Guzzle\Http\Message\Request’, ‘onRequestError’)), ‘request.error’, object(Event)) in //vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php line 53
at EventDispatcher->dispatch(‘request.error’, object(Event)) in //vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php line 785
at Request->processResponse(array(‘handle’ => object(CurlHandle))) in //vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php line 472
at Request->setState(‘complete’, array(‘handle’ => object(CurlHandle))) in //vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php line 66
at EntityEnclosingRequest->setState(‘complete’, array(‘handle’ => object(CurlHandle))) in //vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php line 359
at CurlMulti->processResponse(object(EntityEnclosingRequest), object(CurlHandle), array(‘msg’ => ‘1’, ‘result’ => ‘0’, ‘handle’ => ‘Resource id #12’)) in //vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php line 284
at CurlMulti->processMessages() in //vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php line 245
at CurlMulti->perform() in //vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php line 140
at CurlMulti->send() in //vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php line 105
at CurlMultiProxy->send() in //vendor/guzzle/guzzle/src/Guzzle/Http/Client.php line 396
at Client->send(object(EntityEnclosingRequest)) in //vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php line 263
at Request->send() in //vendor/gonzalo123/silex-twitter-login/lib/SilexTwitterLogin.php line 108
at SilexTwitterLogin->{closure}()
at call_user_func_array(object(Closure), array()) in //vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 129
at HttpKernel->handleRaw(object(Request), ‘1’) in //vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php line 73
at HttpKernel->handle(object(Request), ‘1’, true) in //vendor/silex/silex/src/Silex/Application.php line 504
at Application->handle(object(Request)) in //vendor/silex/silex/src/Silex/Application.php line 481
at Application->run() in //public_html/index.php line 207
Fixed it, my .htaccess url rewrite didn’t process get-parameters correctly.
Changing
RewriteRule (.*) /index.php?param=$1 [L]
to
RewriteRule (.*) /index.php?param=$1 [QSA,L]
fixed the problem.
cool! I had a small nightmare when twitter updated the api (that’s because I said to ensure that you are using the last version) and afaik it works now (until the api change again as usual 🙂 )