3 * Laconica, the distributed open-source microblogging tool
5 * Class for doing OAuth authentication against Twitter
9 * LICENCE: This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * @author Zach Copely <zach@controlyourself.ca>
25 * @copyright 2009 Control Yourself, Inc.
26 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27 * @link http://laconi.ca/
30 if (!defined('LACONICA')) {
35 * Class for doing OAuth authentication against Twitter
37 * Peforms the OAuth "dance" between Laconica and Twitter -- requests a token,
38 * authorizes it, and exchanges it for an access token. It also creates a link
39 * (Foreign_link) between the Laconica user and Twitter user and stores the
40 * access token and secret in the link.
44 * @author Zach Copley <zach@controlyourself.ca>
45 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
46 * @link http://laconi.ca/
49 class TwitterauthorizationAction extends Action
52 * Initialize class members. Looks for 'oauth_token' parameter.
54 * @param array $args misc. arguments
56 * @return boolean true
58 function prepare($args)
60 parent::prepare($args);
62 $this->oauth_token = $this->arg('oauth_token');
70 * @param array $args is ignored since it's now passed in in prepare()
74 function handle($args)
76 parent::handle($args);
78 if (!common_logged_in()) {
79 $this->clientError(_('Not logged in.'), 403);
82 $user = common_current_user();
83 $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
85 // If there's already a foreign link record, it means we already
86 // have an access token, and this is unecessary. So go back.
89 common_redirect(common_local_url('twittersettings'));
92 // $this->oauth_token is only populated once Twitter authorizes our
93 // request token. If it's empty we're at the beginning of the auth
96 if (empty($this->oauth_token)) {
97 $this->authorizeRequestToken();
99 $this->saveAccessToken();
104 * Asks Twitter for a request token, and then redirects to Twitter
109 function authorizeRequestToken()
113 // Get a new request token and authorize it
115 $client = new TwitterOAuthClient();
117 $client->getRequestToken(TwitterOAuthClient::$requestTokenURL);
119 // Sock the request token away in the session temporarily
121 $_SESSION['twitter_request_token'] = $req_tok->key;
122 $_SESSION['twitter_request_token_secret'] = $req_tok->secret;
124 $auth_link = $client->getAuthorizeLink($req_tok);
126 } catch (TwitterOAuthClientException $e) {
127 $msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
128 $e->getCode(), $e->getMessage());
129 $this->serverError(_('Couldn\'t link your Twitter account.'));
132 common_redirect($auth_link);
136 * Called when Twitter returns an authorized request token. Exchanges
137 * it for an access token and stores it.
141 function saveAccessToken()
144 // Check to make sure Twitter returned the same request
145 // token we sent them
147 if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
148 $this->serverError(_('Couldn\'t link your Twitter account.'));
153 $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
154 $_SESSION['twitter_request_token_secret']);
156 // Exchange the request token for an access token
158 $atok = $client->getAccessToken(TwitterOAuthClient::$accessTokenURL);
160 // Test the access token and get the user's Twitter info
162 $client = new TwitterOAuthClient($atok->key, $atok->secret);
163 $twitter_user = $client->verifyCredentials();
165 } catch (OAuthClientException $e) {
166 $msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
167 $e->getCode(), $e->getMessage());
168 $this->serverError(_('Couldn\'t link your Twitter account.'));
171 // Save the access token and Twitter user info
173 $this->saveForeignLink($atok, $twitter_user);
175 // Clean up the the mess we made in the session
177 unset($_SESSION['twitter_request_token']);
178 unset($_SESSION['twitter_request_token_secret']);
180 common_redirect(common_local_url('twittersettings'));
184 * Saves a Foreign_link between Twitter user and local user,
185 * which includes the access token and secret.
187 * @param OAuthToken $access_token the access token to save
188 * @param mixed $twitter_user twitter API user object
192 function saveForeignLink($access_token, $twitter_user)
194 $user = common_current_user();
196 $flink = new Foreign_link();
198 $flink->user_id = $user->id;
199 $flink->foreign_id = $twitter_user->id;
200 $flink->service = TWITTER_SERVICE;
202 $creds = TwitterOAuthClient::packToken($access_token);
204 $flink->credentials = $creds;
205 $flink->created = common_sql_now();
207 // Defaults: noticesync on, everything else off
209 $flink->set_flags(true, false, false, false);
211 $flink_id = $flink->insert();
213 if (empty($flink_id)) {
214 common_log_db_error($flink, 'INSERT', __FILE__);
215 $this->serverError(_('Couldn\'t link your Twitter account.'));
218 save_twitter_user($twitter_user->id, $twitter_user->screen_name);