Codeigniter Sparks oAuth 2 plugin example controller

This post shows an example controller class which allows you to log in to Codeigniter application via external oAuth 2 system like facebook or google. It uses multi-provider oAuth 2 client package from Sparks repository. Sparks is a package management system for Codeigniter that allows you to install external libraries. I recommend to do it with ssh, but there is also a possibility of manual installation for those who can’t use shell.

You can install oAuth 2 package from http://getsparks.org/packages/oauth2/versions/HEAD/show

Things to notice about oAuth 2 package:

1. It uses url helper, so you should load it (I recommend auto loading – http://ellislab.com/codeigniter%20/user-guide/general/autoloader.html, url helper is one of the most commonly used Codeigniter helper), otherwise the following error will be shown:

Fatal error: Call to undefined function site_url() in /sparks/oauth2/0.4.0/libraries/Provider.php on line 76

2. I’ve found a bug in /sparks/oauth2/0.4.0/libraries/Provider/Blooie.php, function url_access_token() is not closed (just add } afterwords to fix it).
Not many use blooie, thats why this is not fixed yet I guess 🙂

3. Codeigniter session must be initialized, see http://ellislab.com/codeigniter%20/user-guide/libraries/sessions.html

Every oAuth service must provide you with an id, and secret string to make you use it. That usually requires to register an app in oAuth provider system. Presented class reads provider data from config file (db is also a good or even better idea). The following is an empty example for facebook and google credentails stored in /application/config/config.php:

$config['oauthProvidersData'] = array(
    'facebook' => array(
        'id' => '',
        'secret' => ''
    ),
    'google' => array(
        'id' => '',
        'secret' => ''
    )
);

You should obviously fill it with a proper data taken from oAuth provider. Nice thing about this solution is when you want to add new oAuth service, there is no need to modify anything more than config file, (much better than hardcoding it within class file).

My goal is to let user just click on facebook or google icon, and be logged. During the first visit user must always accept permissions of our app, and that’s it. If user is visiting controller and agrees for permissions for the first time, than a new user (db row) will be created. During next login the user will be loaded from db, basing on oAuth user id (taken from a provider), and the name of a service. These two variables are always unique together, so it is safe to base on that set of credentials.

Path to run controler is /login/oauth/{providerName} considering mod_rewite being activated. I use my own User model, and SessionManager library, but because of the comments it should be easy to understand what they do.

class Login extends CI_Controller {

    public function __construct() {
        parent::__construct();
    }

    /**
     * Gets user data array from oauth service
     * than runs loginOauthUser
     * @param string $strProviderName
     */
    public function oauth($strOauthProviderName) {
        $this->load->spark('oauth2/0.4.0');

        // create oauth provider object
        $arrOauthProvidersData = $this->config->item('oauthProvidersData');
        $oProvider = $this->oauth2->provider($strOauthProviderName, $arrOauthProvidersData[$strOauthProviderName]);

        // get user data array
        if ($this->input->get('code')) {
            $strToken = $oProvider->access($this->input->get('code'));
            $arrOauthUserData = $oProvider->get_user_info($strToken);
            $this->loginOauthUser($strOauthProviderName, $arrOauthUserData);
        } else {
            $strAuthUrl = $oProvider->authorize();
            // redirects this page which is needed to exchange data between servers
            redirect($strAuthUrl);
        }

        // user canceled permissions request - go to home page
        if ($this->input->get('error')) {
            redirect(base_url());
        }
    }

    /**
     * Logs user in, if it exists in database
     * Creates new one if doesn't
     * Restores session and redirects to home page after that
     * @param string $strOauthProvider
     * @param array $arrUserData
     */
    private function loginOauthUser($strOauthProviderName, $arrOauthUserData) {
        $this->load->model('User');
        $oUser = new User();
        $oUser->setOauthId($arrOauthUserData['uid']);
        $oUser->setOauthProvider($strOauthProviderName);

        try {
            // try to authorize
            $oUser->authorize(); // throws an exception on faliture, loads object on success
        } catch (Exception $exc) {
            // if log in incorrect -> user doesn't exist -> create new one
            $oUser->setName($arrOauthUserData['name']);
            $oUser->setEmail($arrOauthUserData['email']);
            $oUser->create();
        }

        // write user data to session and go to main page
        $this->sessionmanager->restoreUserData($oUser);
        redirect(base_url());
    }

}

Leave a Reply

Your email address will not be published. Required fields are marked *