├── README.md ├── config ├── autoload.php └── oauth.php ├── language └── english │ └── messages_lang.php ├── libraries ├── oauth.php └── providers │ ├── facebook.php │ └── twitter.php └── spark.info /README.md: -------------------------------------------------------------------------------- 1 | # THIS CODE IS NO LONGER MAINTAINED. IF YOU WOULD LIKE TO BECOME THE NEW MAINTAINER FOR THIS PROJECT, PLEASE MESSAGE ME. 2 | 3 | # Codeigniter Oauth 4 | 5 | Helps you work with different Oauth providers to authorize users with your application with a single input and response format, allowing you to pass the authentication mechanism as a variable and simplify your underlying implementation. 6 | 7 | Note that this spark ONLY provides the authorization mechanism. MAKE SURE you put your specific implementation details in the config file. 8 | 9 | ## Currently Supported 10 | 11 | Facebook and Twitter are currently supported. 12 | 13 | ## TODO 14 | 15 | This spark is a work in progress. Things to be added: 16 | 17 | - Lots of refactoring 18 | - Responses in lang file (sounds like an easy pull request to me!) 19 | - More Oauth providers 20 | 21 | ## Installing 22 | 23 | Available via Sparks. For info about how to install sparks, go here: http://getsparks.org/install 24 | 25 | You can then load the spark with this: 26 | 27 | ```php 28 | $this->load->spark('codeigniter-oauth/'); 29 | ``` 30 | 31 | ## Usage Example 32 | 33 | ```php 34 | $starting_url = 'welcome'; 35 | 36 | $seg = $this->uri->segment(1); 37 | if($seg === $starting_url) 38 | { 39 | $type = 'twitter'; 40 | $this->oauth->authorize($type); 41 | } 42 | else 43 | { 44 | $result = $this->oauth->authorize_result($type); 45 | if($result->status === 'success') 46 | { 47 | (isset($result->token2)) 48 | ? $get_auth = $this->oauth->access($type, $result->token, $result->token2) 49 | : $get_auth = $this->oauth->access($type, $result->token); 50 | 51 | var_dump($get_auth);exit; 52 | } 53 | else 54 | { 55 | var_dump($result); 56 | } 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /config/autoload.php: -------------------------------------------------------------------------------- 1 | array( 5 | 'client_id' => '', 6 | 'redirect_uri' => 'http://codeigniter.local/', 7 | 'app_secret' => '' 8 | ), 9 | 'twitter' => array( 10 | 'redirect_uri' => 'http://codeigniter.local/', 11 | 'consumer_key' => '', 12 | 'key_secret' => '' 13 | ) 14 | ); -------------------------------------------------------------------------------- /language/english/messages_lang.php: -------------------------------------------------------------------------------- 1 | ci = &get_instance(); 21 | $this->ci->load->config('oauth', TRUE); 22 | $this->ci->lang->load('messages'); 23 | $this->ci->load->library('session'); 24 | $this->ci->load->helper('url'); 25 | } 26 | 27 | /** 28 | * Make a call. Uses other helper methods to make the request. 29 | * 30 | * @param string The login method to use 31 | * @param array $params[0] is the login method, $params[1] are the params for the request 32 | * @return object Should return a success or failure, along with a response. 33 | */ 34 | public function __call($method, $params) 35 | { 36 | $loaded = $this->_load_module($params[0], $method); 37 | if($loaded) 38 | { 39 | return (isset($params[1])) 40 | ? $this->type->$method($params[1]) 41 | : $this->type->$method(); 42 | } 43 | else 44 | { 45 | return $this->response('failure', array( 46 | 'error' => $this->ci->lang->line('error_request_denied') 47 | ) 48 | ); 49 | } 50 | } 51 | 52 | /** 53 | * Try to load an authentication module 54 | * 55 | * @param string The authentication module to load 56 | * @return mixed Will return bool if file is not found. Will return file as object if found. 57 | */ 58 | private function _load_module($module, $method) 59 | { 60 | $module_location = dirname(__FILE__).'/providers/'.$module.'.php'; 61 | if (!is_file($module_location)) 62 | { 63 | return FALSE; 64 | } 65 | 66 | if(!class_exists($module)) 67 | { 68 | ob_start(); 69 | include $module_location; 70 | ob_get_clean(); 71 | 72 | $this->type = new $module($this); 73 | } 74 | 75 | if(method_exists($this->type, $method)) 76 | { 77 | return TRUE; 78 | } 79 | } 80 | 81 | /** 82 | * Build the request to the Oauth Provider 83 | * 84 | * @param array Params to set 85 | * @param string The method to use (such as POST) 86 | * @param string The endpoint for the reuest 87 | * @param string The secret key 88 | * @return string Response from the _http call 89 | */ 90 | public function make_request($params, $method, $endpoint, $secret) 91 | { 92 | // BUILD SIGNATURE 93 | // encode params keys, values, join and then sort. 94 | $keys = $this->_urlencode_rfc3986(array_keys($params)); 95 | $values = $this->_urlencode_rfc3986(array_values($params)); 96 | $params = array_combine($keys, $values); 97 | uksort($params, 'strcmp'); 98 | 99 | // convert params to string 100 | foreach ($params as $k => $v) {$pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v);} 101 | $concatenatedParams = implode('&', $pairs); 102 | 103 | // form base string (first key) 104 | $baseString= "$method&".$this->_urlencode_rfc3986($endpoint)."&".$this->_urlencode_rfc3986($concatenatedParams); 105 | // form secret (second key) 106 | $secret = $this->_urlencode_rfc3986($secret)."&"; 107 | // make signature and append to params 108 | $params['oauth_signature'] = $this->_urlencode_rfc3986(base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE))); 109 | 110 | // BUILD URL 111 | // Resort 112 | uksort($params, 'strcmp'); 113 | // convert params to string 114 | foreach ($params as $k => $v) {$urlPairs[] = $k."=".$v;} 115 | $concatenatedUrlParams = implode('&', $urlPairs); 116 | // form url 117 | $url = $endpoint."?".$concatenatedUrlParams; 118 | 119 | // Send to cURL 120 | return $this->_http($url); 121 | } 122 | 123 | /** 124 | * Make the Curl Call to the Oauth Proivder 125 | * 126 | * @param string The URL to make the call to 127 | * @param array Array of post fields 128 | * @return mixed Could vary per provider 129 | */ 130 | private function _http($url, $post_data = null) 131 | { 132 | $ch = curl_init(); 133 | 134 | curl_setopt($ch, CURLOPT_URL, $url); 135 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); 136 | curl_setopt($ch, CURLOPT_TIMEOUT, 30); 137 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 138 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 139 | 140 | if(isset($post_data)) 141 | { 142 | curl_setopt($ch, CURLOPT_POST, 1); 143 | curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); 144 | } 145 | 146 | $response = curl_exec($ch); 147 | $this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); 148 | $this->last_api_call = $url; 149 | 150 | return $response; 151 | } 152 | 153 | /** 154 | * URL Encode the request 155 | * 156 | * @param mixed The input array / string 157 | * @return mixed 158 | */ 159 | private function _urlencode_rfc3986($input) 160 | { 161 | if (is_array($input)) { 162 | return array_map(array('Oauth', '_urlencode_rfc3986'), $input); 163 | } 164 | else if (is_scalar($input)) { 165 | return str_replace('+',' ',str_replace('%7E', '~', rawurlencode($input))); 166 | } 167 | else{ 168 | return ''; 169 | } 170 | } 171 | /** 172 | * Parses an XML response and creates an object using SimpleXML 173 | * 174 | * @param string raw xml string 175 | * @return object response object 176 | */ 177 | public function parse_xml($xml_str) 178 | { 179 | $xml_str = trim($xml_str); 180 | $xml_str = preg_replace('/xmlns="(.+?)"/', '', $xml_str); 181 | if($xml_str[0] != '<') 182 | { 183 | $xml_str = explode('<', $xml_str); 184 | unset($xml_str[0]); 185 | $xml_str = '<'.implode('<', $xml_str); 186 | } 187 | 188 | $xml = new SimpleXMLElement($xml_str); 189 | 190 | return $xml; 191 | } 192 | 193 | /** 194 | * Normalize the response 195 | * 196 | * @param string The reponse status (success or failure) 197 | * @return object The response status and details 198 | */ 199 | public function response($status, $details) 200 | { 201 | $return = array( 202 | 'status' => $status 203 | ); 204 | 205 | if(isset($details['token'])) $return['token'] = $details['token']; 206 | 207 | if(isset($details['token2'])) $return['token2'] = $details['token2']; 208 | 209 | if(isset($details['error'])) $return['error'] = $details['error']; 210 | 211 | if(isset($details['user'])) $return['user'] = $details['user']; 212 | 213 | return (object) $return; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /libraries/providers/facebook.php: -------------------------------------------------------------------------------- 1 | oauth = $oauth; 38 | $this->_config = $this->oauth->ci->config->item('facebook', 'oauth'); 39 | } 40 | 41 | /* 42 | * Get an authorization code from Facebook. Redirects to Facebook, which this redirects back to the app using the redirect address you've set. 43 | */ 44 | public function authorize() 45 | { 46 | $state = md5(uniqid(rand(), TRUE)); 47 | $this->oauth->ci->session->set_userdata('state', $state); 48 | 49 | $params = array( 50 | 'client_id' => $this->_config['client_id'], 51 | 'redirect_uri' => $this->_config['redirect_uri'], 52 | 'state' => $state, 53 | 'scope' => 'email' 54 | ); 55 | 56 | $url = $this->_authorize_endpoint.http_build_query($params); 57 | redirect($url); 58 | } 59 | 60 | /* 61 | * Get the authorization result 62 | * 63 | * @return array The response 64 | */ 65 | public function authorize_result() 66 | { 67 | if(isset($_GET['code'])) 68 | { 69 | if($this->oauth->ci->session->userdata('state') !== $_GET['state']) 70 | { 71 | return $this->oauth->response('failure', array( 72 | 'error' => $this->oauth->ci->lang->line('error_xsfr_victim') 73 | ) 74 | ); 75 | } 76 | else 77 | { 78 | return $this->oauth->response('success', array( 79 | 'token' => $_GET['code'], 80 | 'state' => $_GET['state'] 81 | ) 82 | ); 83 | } 84 | } 85 | 86 | if(isset($_GET['error'])) 87 | { 88 | return $this->oauth->response('failure', array( 89 | 'error' => $_GET['error_description'] 90 | ) 91 | ); 92 | } 93 | } 94 | 95 | /* 96 | * Get access to the API 97 | * 98 | * @param string The access code 99 | * @return object Success or failure along with the response details 100 | */ 101 | public function access($code) 102 | { 103 | $params = array( 104 | 'client_id' => $this->_config['client_id'], 105 | 'redirect_uri' => $this->_config['redirect_uri'], 106 | 'client_secret' => $this->_config['app_secret'], 107 | 'code' => $code 108 | ); 109 | 110 | $url = $this->_access_token_endpoint.http_build_query($params); 111 | 112 | $response = file_get_contents($url); 113 | $params = null; 114 | parse_str($response, $params); 115 | 116 | if(isset($params['error'])) 117 | { 118 | return $this->oauth->response('failure', array( 119 | 'error' => $params['error->message'] 120 | ) 121 | ); 122 | } 123 | else 124 | { 125 | $params = http_build_query(array( 126 | 'access_token' => $params['access_token'] 127 | ) 128 | ); 129 | $graph_url = $this->_graph_url.$params; 130 | $user = json_decode(file_get_contents($graph_url)); 131 | 132 | return $this->oauth->response('success', array( 133 | 'user' => array( 134 | 'id' => $user->id, 135 | 'name' => $user->name, 136 | 'username' => $user->username, 137 | 'email' => $user->email 138 | ) 139 | ) 140 | ); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /libraries/providers/twitter.php: -------------------------------------------------------------------------------- 1 | oauth = $oauth; 33 | $this->_config = $this->oauth->ci->config->item('twitter', 'oauth'); 34 | } 35 | 36 | /* 37 | * Request authorization 38 | */ 39 | public function authorize() 40 | { 41 | $token = null; 42 | 43 | $params = array( 44 | "oauth_version" => "1.0", 45 | "oauth_nonce" => time(), 46 | "oauth_timestamp" => time(), 47 | "oauth_consumer_key" => $this->_config['consumer_key'], 48 | "oauth_signature_method" => "HMAC-SHA1" 49 | ); 50 | 51 | parse_str($this->oauth->make_request($params, 'GET', $this->_request_token_endpoint, $this->_config['key_secret']), $token); 52 | redirect($this->_authenticate_endpoint.'?oauth_token='.$token['oauth_token']); 53 | } 54 | 55 | /* 56 | * Get the authorization result 57 | * 58 | * @return array The response 59 | */ 60 | public function authorize_result() 61 | { 62 | if(isset($_GET['oauth_verifier']) && isset($_GET['oauth_token'])) 63 | { 64 | 65 | return $this->oauth->response('success', array( 66 | 'token' => $_GET['oauth_token'], 67 | 'token2' => $_GET['oauth_verifier'] 68 | ) 69 | ); 70 | } 71 | 72 | if(isset($_GET['denied'])) 73 | { 74 | return $this->oauth->response('failure', array( 75 | 'error' => $this->oauth->ci->lang->line('error_request_denied') 76 | ) 77 | ); 78 | } 79 | } 80 | 81 | /* 82 | * Access a User's Profile 83 | * 84 | * @return array The response 85 | */ 86 | public function access($token = null, $verifier = null) 87 | { 88 | $results = null; 89 | 90 | $params = array( 91 | 'oauth_consumer_key' => $this->_config['oauth_consumer_key'], 92 | 'oauth_nonce' => time(), 93 | 'oauth_signature_method' => 'HMAC-SHA1', 94 | 'oauth_token' => $token, 95 | 'oauth_timestamp' => time(), 96 | 'oauth_verifier' => $verifier, 97 | 'oauth_version' => '1.0' 98 | ); 99 | 100 | $request = $this->oauth->make_request($params, 'POST', $this->_access_endpoint, $this->_config['key_secret']); 101 | 102 | if($request[0] == '<') 103 | { 104 | $parsed = (array) $this->oauth->parse_xml($request); 105 | 106 | if(isset($parsed['error'])) 107 | { 108 | return $this->oauth->response('failure', array( 109 | 'error' => $parsed['error'] 110 | ) 111 | ); 112 | } 113 | } 114 | else 115 | { 116 | parse_str($request, $results); 117 | return $this->oauth->response('success', array( 118 | 'user' => array( 119 | 'username' => $results['screen_name'], 120 | 'id' => $results['user_id'] 121 | ) 122 | ) 123 | ); 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /spark.info: -------------------------------------------------------------------------------- 1 | # This is the spark-sdk specification. It's in a magical format without a name. 2 | # Use this format while developing your own sparks! 3 | 4 | # This is the spark name. This should be the registered name of the spark. 5 | name: codeigniter-oauth 6 | 7 | # This is the current version of this spark. All sparks should be in 8 | # x.x.x format. Validation will fail otherwise. 9 | version: 0.0.2 10 | 11 | # This is the version of CodeIgniter this spark is compatible up to. It should 12 | # be in x.x.x format 13 | compatibility: 2.0.0 14 | 15 | # These are other sparks which this spark needs in order to work correctly. 16 | # Dependencies should be in NAME: VERSION format, where NAME is an existing 17 | # spark name, and VERSION is a version in x.x.x format. 18 | #dependencies: 19 | # spark-2: 1.0.0 20 | --------------------------------------------------------------------------------