Thursday, September 12, 2013

Adding OAuth2 to a CodeIgniter Project

Lately, I've been adding OAuth2 (via Google) to some of our internal administrative web applications and I've been pretty happy with them. I especially love how this gets me out of worrying about setting up usernames & passwords, password reset mechanisms and liability for a reused credential. OAuth2 just has a bucket full of win, once you get your head around it & get used to it.

I had a hard time, though, getting my head around it. Sure, there are lots of technical docs & specs, but nothing to really step you through it. So I thought I'd share my approach here, in the case it might help others incorporate this awesome system. I'll admit that my approach is still going through refinements and I definitely welcome input, so let me know if you have ideas or suggestions.

First, I'm using CodeIgniter and Google. If you want to use Twitter, Facebook or LinkedIn, this post is not for you. If you're not using CodeIgniter, this post is probably not for you (though you may be able to give it a read and see if it helps with your PHP project).

The first step is to download Google APIs Client Library for PHP. I save it in the libraries folder underneath CodeIgniter's application folder. Then I log into the Google API Console system and either create or use an existing project.

Then I create a new controller called login, which has 5 methods:

  • relogin: Basically, this simply shows a login page with a button to "Login with Google." This page also has a revoke button, which Google suggests. 
  • not_approved: This is another simple method which shows a screen that tells the user that while they're logged in, their account hasn't been setup with permission to do the specific task they're trying to do.
  • logout: Destroys the website's cookie and redirects them to the relogin method URL.
  • revoke: Sets a session variable that the user wants to revoke access and redirects the user to the login method URL.
  • index: This is where the bulk of the login logic lies. Include the Google PHP libraries, setup the client and then go through a series of checking if a code get query parameter was passed in or if the access token is already in the session and redirects back to itself to authenticate the user.

I want to explain a few parameters of setting up the Google Client. The ID, Secret and API Key are standard and you get those from the Google API Console. But the other three parameters are things I've learned from experience. setRedirectUri + CodeIgniter's site_url() parameter makes the code very portable as you move from server to server. Just make sure that you setup each server & URI as a valid redirect in your project settings. I use array( 'openid', 'email', 'profile' ) for the setScopes parameter, which gives me some great information to tuck away in my user table. Other scopes are available should you want to do more Google-y services on behalf of your users. Lastly (and most importantly!) is the setApprovalPrompt to auto. If you don't, the default behavior prompts the user to verify your app every time they need to login. Using auto provides a much better user experience, in my opinion - not sure why it isn't the default behavior.

Then I create a few views that the login controller will be using: login and blacklist. The blacklist view just has a simple message saying that the administrator needs to approve their account. I add an email link so the user can prod me if they've been waiting a while.

Then I create a user model that is tied to a table I create that basically holds the information that comes back from the token. In my model, I have a nice utility function that either updates the existing user (based on their Google Profile ID #) or inserts them and returns the primary key ID #. My login controller uses this after the user has approved my app to insert or update the user information and then get the ID # and save that in the session.

Finally, I update my primary application controller and add a __construct method (if one doesn't already exist) and then add code to look for a user ID # in the session and if it's either not there or if the token has expired, I destroy the session and redirect the user to the login's index method URL. If it is there and the token is still valid, I check to see if the user has permission. Just because they have a Google Account doesn't mean you necessarily want them to do things.  My table has an extra column for a simple is_admin bit that defaults to 0. I manually set that to 1 for approved administrators. If they don't have permission, then I redirect them to the login's not_approved method URL.

So anyway, there you have it! I hope that helps and again, please feel free to provide feedback in the comments below. Thanks!

1 comment: