Skip to content
rowanwilson edited this page Feb 15, 2013 · 8 revisions

Anyone who has dealt with OAuth, OAuth2, XAuth and OpenID would agree that it's a great approach but hard to code with. For example, if I choose to integrate my application with Twitter OAuth I probably can choose 1 out 5 libraries. What if I now need to integrate with Facebook? or Github?

The problem was later solved in Rails, with OmniAuth and now ported over to PHP (FuelPHP) Land as NinjAuth Package. This is great! However since I already moved from FuelPHP to Laravel I figure Laravel need some OAuth love too and decide to port NinjAuth Package into OneAuth.

Installation

Installation is so damn easy, I assume you already have a Laravel project.

php artisan bundle:install oneauth

Time to register the bundle

Before we can continue with migration, open up application/bundles.php.

<?php

/*
|--------------------------------------------------------------------------
| Bundle Configuration
|--------------------------------------------------------------------------
|
| ...
*/

return array(
	'oneauth' => array('auto' => true),
);

Migrate FTW

Run migration to install oneauth_clients table to your selected database, don't you love it when Schema works with multiple database engine?

php artisan migrate

In case you just started a project, do remember to run php artisan migrate:install.

Let start coding

To make OneAuth work, we need a controller. Let say we want to call ours as Credential_Controller. For this example let say we going to start using OneAuth on twitter provider.

<?php

class Credential_Controller extends OneAuth\Auth\Controller {}

Shouldn't there be any method (or action)? Well for normal usage you don't. There are three action pre-defined in OneAuth\Auth\Controller that already solve everything for you.

Once this is done. Let update your api configuration at bundles/oneauth/config/api.php

<?php

return array(
	/**
	 * Providers
	 * 
	 * Providers such as Facebook, Twitter, etc all use different Strategies such as oAuth, oAuth2, etc.
	 * oAuth takes a key and a secret, oAuth2 takes a (client) id and a secret, optionally a scope.
 	*/
	'providers' => array(
		'twitter' => array(
			'key'    => 'your-app-key',
			'secret' => 'your-app-secret',
		),

	),
);

Remember not to share this anywhere, OAuth server not only authenticate the user but also your application key and secret to ensure it a genuine request.

credential/session/twitter

This is the entry URI to authenticate a user with OAuth or OAuth2, for example if you want to authenticate with Twitter simple create an anchor to {{ HTML::link('credential/session/twitter', 'Sign-in with Twitter') }} and you're done.

credential/callback/twitter

This is the endpoint URI once authentication is complete (or rejected). Successful authentication will result in a new entry to oneauth_clients database table or an update if the entry already exist by checking uid and provider fields.

This path will only be requested by twitter.com, you don't need need to do anything to it :).

Managing failed authentication

How to I show a proper View when there's a failed authentication? With OneAuth you just need to add action_error() method inside Credential_Controller.

<?php

class Credential_Controller extends OneAuth\Auth\Controller 
{
	/**
	 * View proper error message when authentication failed or cancelled by user
	 *
	 * @param   String  	$provider       Provider name, e.g: twitter, facebook, google …
	 * @param   String		$e              Error Message
	 */
	protected function action_error($provider = null, $e = '')
	{
		return View::make('auth.errors', compact('provider', 'e'));
	}
}

Shouldn't we show something when user logged in or register?

This is the point of bundles/oneauth/config/urls.php, you can define the relevant path for registration page, login page, after logged-in landing page, callback url (should refer to the Credential_Controller path).

For this example, let say you want to use Credential_Controller for login and registration too and once user registered or logged in redirect to home. All you need to do is:

<?php

return array(
	'registration' => 'credential/register',
	'login'        => 'credential/login',
	'callback'     => 'credential/callback',

	'registered'   => 'home',
	'logged_in'    => 'home',
);

Registration and Logged-in

<?php

class Credential_Controller extends OneAuth\Auth\Controller 
{
	/**
	 * Registration Page
	 */
	public function action_register()
	{
		if ($_POST)
		{
			// it a POST Request, you should validate the form
			
			$user           = new User;
			$user->username = Input::get('username');
			$user->password = Hash::create(Input::get('password'));
			$user->email    = Input::get('email');
			
			$user->save();
			
			return OneAuth\Auth\Core::redirect('registered'); // redirect to /home
		}
		
		return View::make('auth.register');
	}
	
	/**
	 * Login Page
	 */
	public function action_login()
	{
		if ($_POST)
		{
			// it a POST Request, you should validate the form
			
			$login = array(
				'username' => Input::get('username'), 
				'password' => Input::get('password')
			);

			if (Auth::attempt($login))
			{
				// get logged user id.
				$user_id = Auth::user()->id;
	
				// Synced it with oneauth, this will create a relationship between
				// `oneauth_clients` table with `users` table.
				Event::fire('oneauth.sync', array($user_id));
			
				return OneAuth\Auth\Core::redirect('logged_in'); // redirect to /home
			} 
		}
		
		return View::make('auth.login');
	}
}

Yes you're finally done.