Codeigniter: oauth Login

How to integrate oauth login in any web application using CodeIgniter oauth library? This tutorial features CI class and views to integrate oauth authentication system from popular social networks like Facebook, Twitter, Tumblr, LinkedIn.

Install oauth library using spark

php tools/spark install -v0.3.1 oauth

to install oauth version 2 library

php tools/spark install -v0.3.1 oauth2

If you are new to spark the following link helps you to install for your codeigniter application. 

Install CodIgniter Spark

This library supports following platforms. 

oauth version 1 

  • Twitter
  • LinkedIn
  • Tumblr
  • Dropbox
  • Flickr
  • Google

oauth version 2

  • Facebook
  • Foursquare
  • Github
  • Instragram
  • Paypal
  • Soundcloud
  • Windows Live
  • Yandex
  • Mailru
  • Blooie
  • MailChimp
Create simple login Page

Create simple login page to start with. The login page simply contains links for login options (twitter, facebook, linkedin, tumblr). 

Each link points to the CI controller class to handle the login request. 

Here is the html content of the login page. Utilizes bootstrap and font-awesome for these social network icons. 

Html content for login page.
 <div class="span4 loginlinks">
            <form class="form-horizontal well" method="post" id="form" action="/index.php/login/dologin">
                <fieldset>
                    <legend>Sign in with</legend>

            <a href="/auth/oauth2/facebook" class="facebook"> <i class="icon-facebook-sign icon-4x"></i>  </a>

            <a href="/auth/oauth/twitter" class="twitter"> <i class="icon-twitter-sign icon-4x"></i>  </a>

            <a href="/auth/oauth2/google" class="google-plus"> <i class="icon-google-plus-sign icon-4x"></i>  </a>

            <a href="/auth/oauth/linkedin" class="linkedin"> <i class="icon-linkedin-sign icon-4x"></i>  </a>

                    <fieldset
                        </form>
        </div>
Create controller

Now its time to write most important CI class. This class contains two main functions, each for oath and oauth2 authentication. Twitter, LinkedIn, Tumblr uses oauth version 1 authentication sytem while Facebook uses oauth version 2. 

After receiving json data from the api, the controller saves the user information like nickname,name,location, acess-token, secret,  on the database and then the user is stored on the cookie. Until the cookie expires the browser sees the user as logged in with oauth id. 

Here is the controller class code

 <?php
class Auth extends CI_Controller
{
    public function oauth($providername)
    {
        $key=$this->config->item($providername)['key'];
        $secret=$this->config->item($providername)['secret'];

        $this->load->helper('url');

        $this->load->spark('oauth/0.3.1');

        // Create an consumer from the config
        $consumer = $this->oauth->consumer(array(
            'key' => $key,
            'secret' => $secret,
        ));

        // Load the provider
        $provider = $this->oauth->provider($providername);

        // Create the URL to return the user to
        $callback = site_url('auth/oauth/'.$provider->name);

        if ( ! $this->input->get_post('oauth_token'))
        {
            // Add the callback URL to the consumer
            $consumer->callback($callback);

            // Get a request token for the consumer
            $token = $provider->request_token($consumer);

            // Store the token
            $this->session->set_userdata('oauth_token', base64_encode(serialize($token)));

            // Get the URL to the twitter login page
            $url = $provider->authorize($token, array(
                'oauth_callback' => $callback,
            ));

            // Send the user off to login
            redirect($url);
        }
        else
        {
            if ($this->session->userdata('oauth_token'))
            {
                // Get the token from storage
                $token = unserialize(base64_decode($this->session->userdata('oauth_token')));
            }

            if ( ! empty($token) AND $token->access_token !== $this->input->get_post('oauth_token'))
            {
                // Delete the token, it is not valid
                $this->session->unset_userdata('oauth_token');

                // Send the user back to the beginning
                exit('invalid token after coming back to site');
            }

            // Get the verifier
            $verifier = $this->input->get_post('oauth_verifier');

            // Store the verifier in the token
            $token->verifier($verifier);

            // Exchange the request token for an access token
            $token = $provider->access_token($consumer, $token);

            // We got the token, let's get some user data
            $user = $provider->get_user_info($consumer, $token);


            $this->saveData($providername,$token,$user);
        }
    }

    public function oauth2($providername)
    {

        $key=$this->config->item($providername)['key'];
        $secret=$this->config->item($providername)['secret'];

        $this->load->helper('url_helper');

        $this->load->spark('oauth2/0.3.1');

        $provider = $this->oauth2->provider($providername, array(
            'id' => $key,
            'secret' => $secret,
        ));

        if ( ! $this->input->get('code'))
        {
            // By sending no options it'll come back here
            $provider->authorize();
        }
        else
        {
            // Howzit?
            try
            {
                $token = $provider->access($_GET['code']);
                $user = $provider->get_user_info($token);
                $this->saveData($providername,$token,$user);

            }

            catch (OAuth2_Exception $e)
            {
                show_error('That didnt work: '.$e);
            }

        }
    }


    private function saveData($providername,$token,$user)
    {
        //var_dump($user);
        //return;
        $usertoken= $token->access_token;
        $usersecret= $token->secret;

        $uid=$user['uid'];

        $nickname= array_key_exists('nickname',$user)?$user['nickname']:$uid;
        $name =array_key_exists('name',$user)? $user['name']:null;
        $location= array_key_exists('location',$user)?$user['location']:null;
        $description= array_key_exists('description',$user)?$user['description']:null;
        $profileimage=array_key_exists('image',$user)? $user['image']:null;
        $email=array_key_exists('email',$user)? $user['email']:'';

        $userobj= array('username'=>$nickname,
            'uid'=>$uid,
            'name'=>$name,
            'email'=>$email,
            'location'=>$location,
            'token'=>$usertoken,
            'secret'=>$usersecret,
            'provider'=>$providername,
            'summary'=>$description,
            'profileurl'=>$profileimage,
        );

        $this->load->helper('url');

        $result=$this->db->query("select * from users where uid=? and provider=?",  array($uid,$providername));

        $id=0;
        if($result->row())
        {
            $this->db->where('id',$result->row()->id);
            $this->db->update('users',$userobj);
            $id= $result->row()->id;
        }
        else{
            $this->db->insert('users',$userobj);
            $id = $this->db->insert_id();

        }
        $this->load->library('session');
        $this->session->set_userdata('userid',$id);
        redirect('/index.php/profile/editprofile','refresh');

    }
}
Consumer key and secret

The above controller class utilized the configuration file to retrieve consumer key and secret for any provider. Put these on the myconfig.php file under configs folder as shown on the example below. 

 
$config['twitter']['key']='twitter consumer key';
$config['twitter']['secret']='twitter secret';


$config['tumblr']['key']='tumblr consumer key';
$config['tumblr']['secret']='tumblr secret';


$config['facebook']['key']='facebook key ';
$config['facebook']['secret']='facebook secret';

After the oauth authentication is successfull and data are stored on the database, you may redirect to the profile edit page to let user changes the information. The above controller redirects to the /profile/editprofile page. 

The contorller and view are as below. 

editprofile controller
 public function editprofile()
    {
        $this->load->helper(array('form', 'url'));
        $data = $this->loadcommon();
        $siteid = $this->getsiteid();
        $userid = $this->checklogin();
        if ($userid > 0) {

            if (isset($_GET['err'])) {
                $data['err'] = $_GET['err'];
            }

            $data['user'] = $this->getuser($userid);
            $this->load->view('profile_edit', $data);
        }

public function checklogin($redirect=false)
    {
        $userid = $this->session->userdata('userid');
        if($userid<1 && $redirect)
        {
        	$this->load->helper('url');
			redirect('/login/index?redirect='.current_url() ,'refresh');
			exit;
        }
        return $userid;
    }
    
    

    public function getUser($id)
    {
        $this->db->where('id', $id);
        $records = $this->db->get('users');
        if ($records->num_rows > 0) {
            $res = $records->result();
            return $res[0];
        }
    }
    }
profile_edit view
 <h1> Edit profile</h1>
		<?php if( isset($err)): ?>
			<div class="alert alert-error">
				<?php echo($err) ?>
			</div>
		<?php endif; ?>
		<?php echo form_open_multipart('/index.php/profile/updateprofile');?>
		<p>
			User name: <?php echo($user->username) ?>
		</p>
		
		<p>
			<label>Name </label> <br/>
			<input type="text" name="fullname" value="<?php echo($user->name) ?>" />
		</p>
		<p>
			<label>Info </label> <br/>
			<textarea rows="5" cols="50" name="summary"><?php echo($user->summary) ?></textarea>
		</p>
		<p>
		<label>Profile Image: </label> </br>
		<?php if($user->profileimage !=null): ?>
			<img src="<?php echo( '/profile/thumb/'.$user->id) ?>" />
		<?php endif; ?>
		</p>
		<p>
			<input type="file" name="userfile" size="20" />
		</p>
		<p>
			<input class="btn btn-primary" type="Submit" value="Update" />
		</p>
		</form>