From Android to iPhone, users everywhere have made it abundantly clear that mobile apps are the future, and when it comes to mobile nothing beats a native experience. Native apps mean we need API’s, and API’s need Authentication. That’s why I’m happy to introduce the solution to your mobile Rails backed authentication needs: oPRO. oPRO (pronounced oh-pro) is a Rails engine for adding an OAuth Provider to any Rails app. OAuth 2.0 is how the web authenticates services, if you’ve ever “signed in with Twitter” or “connected with Facebook” you’ve used OAuth. If you’re new to the concept, check out my introduction to OAuth. Otherwise put your programming cap on, cause we’re going to build your first Rails API backed iPhone app.

The Rails App

I’ll assume you’ve got a Rails app already burning a hole in your pocket, but if you don’t you can easily clone one of mine. The Rails app is going to need a User model that we can authenticate against. You will also need authentication on your User model, oPRO has built-in Devise integration, but if you’re using something else you can easily write your own adapter.

Now that you’ve got a working app you’ll need to install oPRO, you’ll start off by adding this code to your Gemfile:

gem 'opro'

Then run

$ bundle install

and then

$ rails g opro:install

This will put a file in initializers/opro.rb and generate some migrations, and add mount_opro_oauth to your routes. If you are using Devise make sure that the auth_strategy inside of of this initializer is set to :devise, otherwise you’ll need to configure a Custom auth adapter:

config.auth_strategy = :devise

Next we need to migrate the database and we’re almost done.

$ rake db:migrate

This gives us a table to store OAuth client app credentials and a table to store access tokens for our users.

Now we need to configure which controllers will allow OAuth, we do this by adding allow_oauth! to a controller. If you have a UsersController go ahead and add it there, this will give any client with API access the ability to hit any actions in this controller.

class UsersController < ApplicationController
  allow_oauth!
end

The allow_oauth! method accepts the same arguments as a before_filter

Boot, and Configure your First Client App

Now that you’ve got oPRO set up, you need to generate an Client App auth token and secret. This is how your main Rails app will keep track of clients, and can be used for whitelisting, blacklisting and rate limiting. Go ahead and start your local server:

$ rails server

Now with your server running on port 3000 you can view the built in documentation if you wish, but for now we need to visit https://localhost:3000/oauth_client_apps/new to generate a client app. Fill out a name for your app such as: my first API app and hit enter. You should be redirected to a page with a secret and a token. Record these, for the purposes of this example we will use these credentials:

Name:       "my first API app"
client id:  "3234myClientId5678"
Secret:     "14321myClientSecret8765"

Now that you’ve got a working Rails app, and it’s acting as an OAuth provider; it’s time to get this party started and make your first Rails backed iPhone app.

The iPhone App

If you’ve never coded Objective C, don’t get too nervous, I’ve already got an app we can start with. To see the app you can go to https://github.com/opro/opro_rails_demo. First we’ll need to clone this locally, go to your project directory (not inside of your rails app) and clone the repository:

$ git clone git@github.com:opro/opro.git

Move into that directory and run:

$ cd opro_iphone_demo
$ gem install cocoapods
$ pod install
$ open "oPRO-Demo.xcworkspace"

Here we are using cocoapods much like bundler to install external dependencies for our iPhone app. This app relies on the excellent AFNetworking and AFOauth2Client written by @mattt from Heroku. After you’ve run the above, xcode should be open. Make sure the target of the application is set for oPRO-Demo and hit run (cmd+r). You should see a screen like this:

If you don’t see that screen you may need to update Xcode, install the iOS developer libraries, or change your target. Try checking the debug logs for output or errors. If you’re new to iOS programming, I recommend big nerd ranch: iOS Programming as a starting point. The iOS course from code school looks promising.

This iPhone demo app uses a Rails backed oPRO app that I’m hosting on Heroku: https://opro-demo.herokuapp.com. Previously I generated credentials for it that you can see if you open OproAPIClient.h:

#define oClientBaseURLString @"https://opro-demo.herokuapp.com/"
#define oClientID            @"5e163ed8c70cc28e993109c788325307"
#define oClientSecret        @"898ca5b48548bb3988b3c8469081fcfb"

You can make sure the demo works with my default Rails app on Heroku by pressing the “Create a Random User button”, this is will hit an endpoint on https://opro-demo.herokuapp.com/ that saves a new user to the database, and returns the randomly generated email and password so the mobile app can log in. This functionality isn’t something you would want to have in your app, but is useful for an OAuth demo.

Once the server responds to your iPhone simulator, the email and password fields should now be filled-in and the “Log In” button should be active. Press it. This will send the email and password to the server along with your client id and client secret. If everything is successful the server will return an access token you can use on behalf of the user. You should be taken to a new screen that has email, twitter, and zip on it. Try modifying one of the fields and submitting the form. When you do this you are changing data on the Rails server as an authenticated user. From now on, any requests you make with the access token mean you are acting on the behalf of that user.

If you didn’t see the fields update look at the client logs and see if you can find any errors. Now that you’ve got a working iPhone app, it’s time to re-purpose this it for your own site.

Your App, Your Way

Now that you’ve verified that the iPhone demo app works with the demo on Heroku we’re going to modify it to work with your local Rails app. First, make sure that you have your local Rails app running:

$ rails server

Now grab the credentials you wrote down earlier after signing up for a client application on your own server. If you didn’t it’s okay, you can go to https://localhost:3000/oauth_client_apps, select an app, and write down the secret and id, for our purposes we will use these:

Name:       "my first API app"
client id:  "3234myClientId5678"
Secret:     "14321myClientSecret8765"

Remember that your credentials will be different. Now inside of OproAPIClient.h replace “https://opro-demo.herokuapp.com/” with “https://localhost:3000/" and replace the oClientID and oClientSecret with your client and secret. If we were using our example values it would be:

#define oClientBaseURLString @"https://localhost:3000/"
#define oClientID            @"3234myClientId5678"
#define oClientSecret        @"14321myClientSecret8765"

Note: your ID and Secret will be different from these, if you try to use the credentials I have here, it won’t work because your local server is different.

Now that you’ve got your credentials in your iPhone App, re-build it by pressing “run” or hitting (cmd+r). If the app didn’t build check the output from xcode. If everything worked you should see the same screen, but clicking “Create a Random User button should not work. Take a look at your local rails server logs to verify that it is receiving requests from the iPhone simulator. You will receive errors in the log if you are using the “random button”.

Since we can’t create a random user, how will we log in? You’ll need to create a user in your database. If you’re using devise you can visit https://localhost:3000/users/sign_up and enter an email and password. Remember the email and password. If you can’t remember where the sign up form is you can always make a new user in the console:

$ rails console
> password = "password"
> email    = "email@example.com"
> User.create(:email => email, :password => password, :password_confirmation => password)
> User.last.email == email # => true

Now you’ve got a user in your database with an email and password. Enter these into the email and password fields in Xcode. Once you’ve entered both fields you should see the “Log In” button become active. Pull up your rails server logs, and then click the “Log In” button on the iPhone simulator, your should see the request come in with the email you gave, and the password filtered out. If the request went well you should see a 200 status response from the server, and the iPhone simulator will show the user edit page.

If you’re using the demo App I provided, you can change any of those fields and hit enter. You should see the request along with the values you set hit your local server.

Note: the iPhone app expects JSON response from your Rails server under the /users update action, so you might need to add a respond_to block.

If you are running your own app and don’t have a “zip” or “twitter” field in your User table, you will get an error if you hit enter. If that is the case you can open EditUserViewController.m and in the updateUser method you will see that we are creating a dictionary (similar to a hash in Ruby) with “email”, “twitter”, and “zip” fields:

[mutableUserParameters setValue:userEmailField.text forKey:@"email"];
[mutableUserParameters setValue:userTwitterField.text forKey:@"twitter"];
[mutableUserParameters setValue:userZipField.text forKey:@"zip"];

If you don’t want to send the “twitter” and “zip” fields you can take these out so that it is only sending the “email” field:

[mutableUserParameters setValue:userEmailField.text forKey:@"email"];

Save and re-run the iPhone app, re-enter credentials and then try modifying the “email” address of your user. Change it to “schneems@example.com”. When you hit enter you should see the new email come in as a request to your server. When everything works will also be able to see this change in your database:

$ rails console
> User.where(:email => "schneems@example.com")

Congrats, you just made your first working API backed Rails app using OAuth! If you’re still having problems, remember to check your Rails log, and the iPhone simulator log. To log to rails you might use:

puts "something happened!!!!!!!!!!!!!"

But in objective-c you would use:

NSLog(@"something happened!!!!!!!!!!!!!")

We’re not quite done with the demo just yet. We might have authenticated you against your local app, but we don’t want to do this every time, let’s make sure the iPhone app remembers us when we power down the phone.

Remember Me

Getting an access token isn’t much good if we don’t remember it. We’re going to see how we store it on the iPhone and how we can use it to authenticate against later.

Go ahead and stop the iPhone simulator, and restart it by pressing run or hitting (cmd+r). When it comes back online you should notice that the “Log In” button is already active, try hitting it right now. What happens? You should see the update user screen with the same email we put in last time, but how did the app remember? Open up OproAPIClient.m again and take a look at setAuthorizationWithToken (trust me after awhile the method names don’t look so bad). You’ll see that we are storing the accessToken and the refreshToken:

[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"kaccessToken"];
[[NSUserDefaults standardUserDefaults] setObject:refreshToken forKey:@"krefreshToken"];

Here we are telling our iPhone app to store these values to disk even after the app is killed, or restarted. Then later we can pull those values from disk when we initialize the API client as we do in the initWithBaseURL method:

  NSString *accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"kaccessToken"];
  NSString *refreshToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"krefreshToken"];

  [self setAuthorizationWithToken:accessToken refreshToken:refreshToken];

Now all we have left to do is write some logic in our controller to make the button available if the user authenticated previously. This is done in OproDemoViewController.m

  // Make the log in button clickable if a user has previously authenticated
  if ( [[OproAPIClient sharedClient] isAuthenticated])  {
    [getAccessTokenButton setEnabled:YES];
    [getAccessTokenButton setHighlighted:YES];
    [getUserCredentialsButton setHighlighted:NO];

  }

That’s all there is to it! Now you’ve got an app that can hit your Rails app and act as an authenticated user.

While this might be your first app, you shouldn’t stop here. You can rip out the OproAPIClient.h and OproAPIClient.m to put in your own custom app, or you could modify this one to meet your needs, this is only a starting point. Before we declare victory over our new found API client and Rails app, let’s deploy to production.

To the Cloud!

Now that we’ve got the client working, we’ll put our app on Heroku where anyone can hit the API without needing access to your localhost. If you don’t have an account you’ll need to sign up at Heroku.com. Once you’ve done that you can install the Heroku Toolbelt and then you can provision an app, in the same directory as your rails project run:

$ heroku login
$ heroku create
Creating smooth-rain-2686.. done, stack is cedar
https://smooth-rain-2686.heroku.com/ | git@heroku.com:smooth-rain-2686

Note: your url and app name will be different.

Once you’ve got your Heroku app provisioned, you’ll need to commit the files to git and to deploy. Run:

$ git add .
$ git commit -m "deploy to heroku"
$ git push heroku master

After a successful push, you should see your app compiling and several steps such as bundle install and rake assets:precompile being run. Once it’s done you’ll need to migrate your database:

$ heroku run rake db:migrate

Now you can hit your app and make sure it is working right, visit the url that was given to you earlier, such as https://smooth-rain-2686.heroku.com/. If you have any problems you can check the logs by running:

$ heroku logs --tail

Now that you’ve got your app running in the cloud, let’s add SSL. SSL will protect your app from people snooping on credentials, it will allow encrypted communication using HTTPS between our iPhone and Rails app. There is an SSL add-on you can add to your Heroku app. To provision this add-on you can go to the the add-on page or run this from the command line:

$ heroku addons:add ssl:endpoint

Once your app is safely running on Heroku you can point your iPhone app to your production server in OproAPIClient.h and don’t forget to use https:// instead of simply https://. You can create a new OAuth client app as we did before by visiting your website /oauth/new, then you’ll want to add your id and secret to the OproAPIClient.h as well and save a user to the postgres database on Heroku. To make sure you’re hitting the right url you can always check the server logs on Heroku:

$ heroku logs --tail

Once you’ve got your site running on Heroku and your iPhone client properly configured you can use your very own iPhone app on your very own production Rails app. Pretty cool, huh?

Finishing up

Today you turned your Rails app into an OAuth 2.0 powered API. You made your first native iPhone app and deployed it’s server to production. Not bad for an afternoon’s work. Now that you’ve got the basics you can learn more about how the authorization in the iPhone app works by visiting the oPRO iPhone App Docs. After that you should read about the configuration available visit the oPRO developer’s docs. If you run into any inaccuracies, or you just want to say hi or show of your oPRO powered app, you can always find me on twitter as @schneems. May the OAuth be with you.


Richard works for Heroku on the Ruby Team and teaches rails classes at the University of Texas. If you like APIs as much as he does, chat him up on the twitters @schneems. If you enjoyed this article you might also enjoy raise “hell”: Better Programming through Exceptions.