2013-09-12

This tutorial will dive into implementing Google Services using the OAuth 2.0 protocol. Read on!

OAuth 2.0 Overview

The OAuth 2.0 protocol provides a simple and secure standard that allows third-party applications to access major service providers like Facebook, G+, and Twitter without compromising user passwords. The whole idea revolves around the existence of an access token, something like a unique key that can identify a user in place of a password. Access tokens are obtained by third-party applications after the user successfully authenticates with a web service. The whole process, known as authorization flow, begins when a user enters his credentials into a login window and finishes when the access token is acquired. The access token is usually refreshed from time to time. With this token, there is no need for any of the user’s personal data or password to be transmitted over the web each time that a client application asks for access on behalf of the user.

If you are not familiar with the OAuth 2.0 protocol you should do some background reading now before continuing this tutorial. Specifically, review the following links:

OAuth 2.0 Documentation and Specification

About OAuth in Wikipedia

In general, the OAuth 2.0 authorization flow adheres to the following pattern:

Let users connect to their online account.

Get an authorization code (i.e. authorization token).

Exchange the authorization code for an access token and a refresh token.

Use the access token to interact with a web service or an API.

Use the refresh token to update the access token when needed.

Google and OAuth 2.0

Google is one of the many third-party web service providers that have adopted the OAuth 2.0 protocol. It provides many APIs for accessing almost all of its services (like Calendar, Blogger, etc.) through client applications and provides guidance on how to implement the authorization flow with various programming languages and platforms. Every application that needs to use any of the Google web services must first register with the Google Developer Console, an administration panel where all the client applications developed by a user are managed. When registering an app in the Console, a client id and a client secret are created specifically for this app. These values, along with some others, are used by OAuth to authorize an app and to obtain the access token. After having registered an application, there are a number of available services that can be integrated into projects. These services are accessed through APIs that are provided for each one. Some of them are free of charge while others require a fee before Google will let you use them beyond a courtesy/trial usage limit.

From this point forward, I’ll assume that you are familiar with OAuth 2.0 principles, so it’s time to visit the Using OAuth 2.0 for Installed Applications documentation from Google. This documentation presents the authorization flow supported by Google for client applications implemented for mobile or desktop platforms and is going to be our guide on the project of this tutorial. Also, I would recommend that you surf around a little using the menu options at the top-left side of the window and the links inside the text in order to gain a deeper understanding on Google services and the way the OAuth 2.0 protocol works.

Project Overview

This project will teach you how to create a class that will contain the OAuth 2.0 client-side implementation for accessing Google’s API and services. This class will be part of a simple demo application. The GUI will be really simple, as we only need to test the class, so we are going to spend a great deal of time actually coding. In order to test the OAuth protocol implementation, we will ask for the user profile information from Google, which will be displayed in our app. Also, in order for our work to be as complete as possible, we will add extra checks and error handling messages. After this class is ready, it can be used in real projects for accessing Google services. Of course, it can be improved or be modified by anyone at any time.

Before we begin writing one line of code, we need to register the demo application in the Google Developers Console. To do this, we’ll need the app’s name. For the sake of our project, I’m using the name GoogleOAuthDemo. If you prefer some other name, make sure to use it instead of mine in the steps that follow.

For now, here is a screenshot of the final product:

1. Register the iOS Application

Step 1

Our first step is to register the iOS application in the Google Developer Console because we need to acquire a Client ID and a Client Secret value pair. So, inside a new browser tab/window, visit the Google Developers website. At the top-right side of the window, a Sign In button exists. Click it and the next window will show up.

If you have an account in any Google service (like gmail, Google+, Drive, etc.) then you can login using the credentials from this account. If you don’t have one already, or you just want to create a new one, now is the time to do it, simply by clicking on the Sign Up button.

In case you are making a new account, enter any required information, create it, and login to the Google Developers website.

Step 2

Once you get connected with the Google Developers account, you might become quite curious about all the stuff this page contains, so go ahead and take a look if you wish. Surely you’ll find some pretty interesting topics. Scroll to the bottom side of the page, until you see the Developer Tools area. Click on the API Console link.

Step 3

When you create an application in the Developers Console, the information regarding it is grouped all together and it’s called a project. Through it, you can manage all the APIs, users, authorization, and more stuff that you use in your applications. I would advise to look at the Help section (at the top-right side of the webpage) if you want to find detailed information about the console.

Let’s get back on track. When you first look at this webpage, you notice a drop-down menu at the top-left side of the webpage, named API Project. If you expand it, you’ll find some extra options, where by using them you can create new projects, delete them, rename them, and more. We don’t need anything from it, so if you have expanded it, click on it to collapse it. Beneath the drop-down menu, there are four options:

Overview

Services

Team

API Access

If you click on the Services option, you’ll see all the services that Google offers with APIs. Next to each service there are some notes indicating which of them require a fee. To use any of them in an application, first you must register your application, then implement the OAuth protocol and finally ask for the appropriate APIs.

Click on the API Access option now. This is the place where we’ll register our new application. Click on the big blue button with the title “Create an OAuth 2.0 client ID…”.

In the popup window, add as the Product Name the Google OAuth 2.0 iOS Implementation Demo value and click on Next.

In the next step, set the following:

Application Type: Installed application

Installed Application Type: iOS

Bundle ID: com.yourdomain.googleoauthdemo (for example, com.gabrieltheodoropoulos.googleoauthdemo)

Click on the Create client ID button now and you are ready. As you can see at the next screenshot, you can easily find the client ID and the client secret values.

You can find out for yourself that you can edit all the information we just entered using the provided links and buttons in the webpage. The data we are going to use in our demo application is:

client ID

client secret

Redirect URI

At this point, the first part of our mission is over. Our app has been registered in the Google Developers Console and we have all the necessary information we want. The hard part though is coming next, where we are going to actually implement the OAuth 2.0 protocol in code.

2. Create the Demo Project

Time to begin building our app. Launch Xcode and create a new project. At the first step, select the Single View Application option from the provided templates.

Next, specify the GoogleOAuthDemo in the Product Name field of the project’s options window.

Lastly, select a place to save your project and click on the Create button.

3. Create the Interface

Step 1

Click on the ViewController.xib file to launch Interface Builder. Drag-and-drop the next subviews on the default view:

A Table View.

A Toolbar.

Also, apart from the default Bar Button Item that the toolbar contains, add:

A Flexible Space Bar Button Item and

A Bar Button Item

Make sure that the one button is at the left side of toolbar, while the second is at the right side of it. The flexible space should be between them.

Step 2

Let’s now do a couple of settings.

Select the View and set its Size to None so it works on 3.5″ iPhone screens as well.

Open the Utilities pane.

Show the Attributes Inspector tab.

In the Simulated Metrics section set the Size to None.

Set the frame of the Table View to: X: 0, Y: 0, Width: 320, Height: 416.

Set the Title of the left Bar Button Item to My Profile.

Set the Title of the right Bar Button Item to Revoke access.

That’s all we want from our interface and this is how it should look now:

4. Setup IBOutlets & IBActions

Step 1

Our interface is prepared, but we need an IBOutlet property to connect the Table View. We also need two IBAction methods if we want our buttons to work. So, while we are in Interface Builder, Click on the middle button of the Editor section on the Xcode toolbar to make the Assistant Editor appear.

Step 2

With the goal of creating the necessary IBOutlet connection, open the Document Outline and perform the following steps:

Control + Click or Right + Click on the Table View.

On the popup menu, click on the New Referencing Outlet.

Drag-and-drop into the Assistant Editor window, just like you see in the next image.

Give a name for the Table View and click on the Connect button. I simply named it table.

Step 3

Let’s create the two IBAction methods now. Apply the following procedure in both the Bar Button Items.

Control + Click or Right + Click on the left Bar Button item.

Click on the Selector option in the Sent Actions section of the popup menu.

Drag-and-drop into the Assistant Editor window.

Set the showProfile as the name for the method and create it.

Give the name revokeAccess to the next IBAction method when you create it. Your ViewController.h file after the IBOutlet property and the IBAction methods should look like this:

5. Create the OAuth 2.0 Protocol Implementation File

Step 1

Even though we added a Table View in the project, we won’t implement its delegate methods for the time being. This is something that we are going to do when the OAuth 2.0 implementation is over. What we are going to do in this step is to create a new file where we will build the OAuth protocol.

On the Project Navigator, do the following:

Control + Click or Right + Click on the GoogleOAuthDemo group.

Select the New File… option from the menu.

Step 2

In the window that appears, select the Objective-C class option as the template for the new file:

Next, at the Subclass of field, select the UIWebView option. Our new class is going to be a subclass of the UIWebView class, because we want to show a web view to the users for letting them sign in with their Google account and grant them access to our application. At the Class field, add the GoogleOAuth value:

On the next step, just click on the Create button to get the new files made.

6. The OAuth 2.0 Flow

In this part, I will shortly describe how the OAuth 2.0 flow will be implemented and how all the necessary checking for the existence of the tokens and the validity of the access token is going to take place. First of all, after the access token has been obtained, it should be stored permanently along with any other info that comes with it. It’s up to the developer to choose the way that all this information will be saved. You may store everything into a database, save it to the user defaults, write everything to files, or use more secure methods in order to keep things safe. In this tutorial, I prefer to save all in plain files, inside the Documents directory of the app.

We are going to create two different files. The access token and any other information that comes with it from Google is going to be stored into the first one, except for the refresh token. The refresh token is going to be saved in another file, because we need to keep it for a longer period than everything else and use it when the access token has expired. Every time that the access token is being refreshed, the contents of the first file are overwritten. Besides that, the refresh token itself is not refreshed that often.

So, having said all that, here is a preview of the protocol’s flow and how it is going to be implemented.

Even though an image equals a thousand words, I would better describe the whole procedure to make it more clear. To elaborate on the authorization process:

In case the file that contains the access token information does not exist…

The URL that we will require an access token from is being formed. All the necessary parameters to authenticate the user are provided. The client ID and client secret values are needed here.

Next, we display a web view inside the app (we don’t call Safari) to let the user sign in to Google. After a successful login, a message from Google with the permissions we ask for is displayed to the user, who should consent if he/she wants to go any further.

An authorization code comes back from Google, which will be exchanged with the access token right after.

A new URL is formed with new parameters. The aim is to exchange the authorization code with the access token.

If the access token is successfully obtained, the caller class is informed via a delegate method. Otherwise, using another delegate method we let the caller class know that the access token was not obtained, so further actions should be taken as needed.

In case the file that contains the access token information already exists…

The access token info is loaded from the file.

The access token is checked to see whether it has expired or not.

If the access token is valid, then the caller class simply gets notified through a delegate method that is valid and these steps end here. Otherwise, a refresh is required (next steps).

If the file that contains the refresh token is not found in the Documents directory, then the whole OAuth flow starts over. If it exists, then the refresh token is loaded.

A new access token is requested. If the refresh token is not valid, a kind of error message will be returned from Google and the user is guided to the beginning again. Otherwise the access token is obtained.

So, let’s see everything step-by-step.

7. Start building

Step 1

At first, open the GoogleOAuth.h file and adopt the next two protocols, simply by declaring them in the @interface header line:

I am pretty sure that it is quite obvious what these delegates are for.

Step 2

Now let’s create an enum type, with the acceptable HTTP method values required for various API calls. For the time being, we’ll create the enum type, but we’ll use it when we’ll implement the API call method.

So, right above the @interface line at the GoogleOAuth.h file, add the following:

Step 3

It’s always useful to use constants for things that we don’t want to make any mistakes about, and that is true for the URL endpoints we want to access during the OAuth flow. For that reason, open the GoogleOAuth.m file and declare the following two constants at the top of the file:

The first URL will be used to access the endpoint for getting the authorization code, which we will exchange then with the access token using the second endpoint. Let’s move on now and let’s declare some private properties that are going to hold some essential data.

Step 4

While working in the GoogleOAuth.m file, inside the private part of the interface, add the following properties. There are comments above each property that explain their purpose:

Note that for the access token there is not a specific NSString property, but we have the accessTokenInfoDictionary NSMutableDictionary for storing all the access token related data in it.

Step 5

Time to do some initializations. Go inside the - (id)initWithFrame:(CGRect)frame and add the following code:

The rest of the initializations will take place inside the methods that they will be used, so for now we are just fine.

8. Define a protocol

Defining a protocol inside a new class is a task that is done usually after most of the class’ functionality has been completed, but in our case it would be nice if we have had the protocol definition prepared before we go any further. What we will actually do is to declare the protocol methods that will be implemented later by the classes that will adopt the protocol. So, inside the GoogleOAuth.h file and above the @interface line, add the next few lines:

Here is a short description of the above methods:

authorizationWasSuccessful : It will be used after a successful authorization, meaning after having obtained a valid access token.

accessTokenWasRevoked : This delegate method will be used when the user revokes all the granted permissions.

responseFromServiceWasReceived:andResponseJSONAsData: : This method will be called every time that a response to an API call is received.

errorOccuredWithShortDescription:andErrorDetails: : Called when a general error occurs.

errorInResponseWithBody: : This delegate method will be called when an error in the HTTP response exists.

Next, inside the @interface, add the next line:

9. Authorization Flow Setup

Step 1

Until now, we declared all the private member variables we are going to need and initialized some of them, we defined constants, delegates, and protocol, so it’s now time to begin implementing the actual authorization flow. The best place to begin from is the “entry” point, a public method that the user will call every time that should be authorized or use an API.

Go to the GoogleOAuth.h file and add the next method declaration:

Step 2

Let’s go to the implementation now. I think it would be better to have the method built first and then discuss it a little bit. Inside the GoogleOAuth.m file add the next snippet:

Let’s talk a little about the way the method that we just wrote works. As you can see, the first thing we do is to store all the values being passed into the method as parameters to the local properties. These are the client ID, the client secret, the scopes array and the UIView that the login webview shall appear within.

A scope indicates an API that the app requests access for.

Next, we check if the access token info file exists or not. In case it exists, we load it using the loadAccessTokenInfo method. We check if it’s valid using the checkIfShouldRefreshAccessToken method and if it’s not, we refresh it by using the refreshAccessToken method. In case the access token is valid and it has not yet expired, we just inform the caller class through the authorizationWasSuccessful delegate method. Finally, if the access token info file doesn’t exist, we simply call the showWebviewForUserLogin method to force the webview to appear and let the user sign in.

All of the methods above will be implemented one by one.

10. Method Preview & Declaration

As you can see for yourself in the snippet above, the method almost in its entirety works using other, private methods. Before going on to the next steps, it is a good idea to declare all the private methods that we are going to implement inside the private @interface section.

In order to make the whole idea easier to understand, I prefer to separate the private methods in two categories:

The first one includes those methods which are part of the authorization flow itself. These are:

The second category includes auxiliary methods whose role is to support the authorization flow by implementing other necessary operations in order the whole procedure properly works. These include:

Besides all the above, we will implement the following delegate method for the webview:

Using it we will “read” the authorization code.

Additionally, we will implement the next NSURLConnection delegate methods:

Let’s move on now and let’s see how all these bind together.

11. Implementing the Authorization Flow

Step 1

Let’s continue by writing the -(void)showWebviewForUserLogin method. This method serves two purposes. The first one is to form the URL (with all the required parameters) that our app will use to get the authorization code. The second is to show a webview to the users, through which they will sign in their Google account and grant access permissions to the app. Let’s see the method first.

A couple of observations now. At first, all the scopes existing in the _scopes array are getting concatenated into one NSString, after having been URL encoded. This is a must, as every special character that might exist in a scope should be replaced with the equivalent URL encoded character (more on this later). A temporary string is being used for concatenation purposes. Inside the concatenated string the scopes are separated using the plus “+” sign.

Next, the URL string is formed. Pay special attention to the parameters it accepts.

We provide:

The authorization code endpoint

The scopes

The redirect URI which is a constant value for installed applications

The client ID that we got from the Google Developers Console

The response_type value which is set to the standard value of code

In the second half of the method, we are simply setting up the webview that will appear to the user. There is nothing particular I should point out here, the code is easy enough. Just note that after setting everything up and calling the loadRequest method the webview is added as a subview to the parent view.

Step 2

Once the user has signed in and has agreed to provide access to our app, the authorization code is returned from Google. Actually, there are two ways to get it. The first one involves the use of cookies, where the authorization code is stored in a cookie file. Google provides a sample on how to use this way. The second one, which is the way I prefer to use, is to get the authorization code from the web view’s page title. Once we acquire it, we are ready to proceed in obtaining the access token.

This is what we are going to do in the only one webview delegate method that we are going to implement. Let’s see this in action.

The authorization code that is returned is in a form similar to code=4/a5F4r45.... That’t why in the above snippet the title is being broken into parts based on the equal sign “=”. After that, we are ready to exchange it for the access token.

Step 3

Now that the authorization token has been obtained, the webview is no longer needed. We will remove it though at the end of the whole process (next step). The NSURLConnection and NSURLRequest classes will be in use from now on. What we have to do in the exchangeAuthorizationCodeForAccessToken method is just to setup all the required parameters that are needed to get the access token and to make a request to the access token endpoint. The most important thing I should point out here is that the POST HTTP method is being used. Here is the method.

Notice the use of the authorization code that we acquired in the previous step.

Step 4

When making a request and using a NSURLConnection, two things may happen. Either the connection will successfully finish, or it will fail. In our case, when a request fails we only want to inform the caller class through the delegate and that’s all. So, let’s write the first NSURLConnection delegate method.

You see how our delegate methods become handy. Let’s go now to the case where the connection is successfully finished and the access token has been received.

Don’t fool yourself by believing that this is going to be the only content of this delegate method. Actually, it’s going to become somehow big, but you shouldn’t mind about that right now.

Note: Do you see the isAPIResponse flag? Well, this is useful for knowing when the response regards an API or the authorization process itself. When it comes under any case that has to do with the authorization process, it becomes NO, as you can see in the access token’s case. You’ll completely understand its significance along the way.

Google returns a JSON object which contains the access token along with other data. The first thing we do is to convert the received data into a string value, so we can easily distinguish what kind of data has been received and properly handle it. By doing so at the beginning of the method, we check whether the access token was received indeed or not, simply by looking for it inside the response string. If it’s there, then…wow, we just obtained the access token! Let’s take care of it now. First, we save it into the file, and we remove the webview from the superview. In case that the access token was obtained during a refresh process, we set the respective flag to NO. Finally, we use our delegate to inform the caller class that the access token has been successfully acquired.

The JSON that is returned is something similar to this one:

At this point, add the following code segment above the if ([_responseJSON rangeOfString:@"access_token"].location != NSNotFound) { line. It is required for dealing with any invalid request that may occur. If you wonder why could this happen, just try to play around with the whole authorization or refresh process and you will easily find out.

Quite important is the next NSURLConnection delegate method too, if you want the above two to properly work.

The authorization flow is now over. However, there is still a lot of work to be done before we will be ready to say that we have a fully implemented class.

12. Refreshing the Access Token

One piece of information that is received along with the access token is the time in seconds that the access token is valid. While the access token is valid, it can be used without any problem when calling APIs. However, when the token expires, a refresh is necessary to take place in the background and a new access token needs to be obtained.

To check if an access token is still valid or not, we will use the checkIfShouldRefreshAccessToken method. We will implement it a little bit later, along with the rest of the auxiliary private methods. For now, let’s focus on the refresh process.

The way we refresh an access token is quite similar to the way we exchange the authorization code for the access token. We set the POST parameters and we perform a NSURLRequest so as to get a new access token. Here is the method:

As you can see, we need only the refresh token that was obtained with the access token, the client ID, the client secret, and the standard value grant_type parameters. Nothing hard or new here.

There are a couple of things I should underline at this point. First of all, a refresh token lasts a lot longer than an access token. That means that a refresh token is not being received every time a refresh procedure is on the way. A refresh token can be used many times and that fact leads to the need for a more permanent way of storage, while the saving place/way of it should be different from the access token’s. The last one may be re-written many times and if the refresh token resides with it, it will be deleted after the first refresh.

Secondly, a refresh token can become invalid as well. In that case, and if the access token needs to be updated, the user must be led to enter login information and provide access permissions once again. This is a case we should predict in our code.

Inside the -(void)connectionDidFinishLoading:(NSURLConnection *)connection delegate method, the case of obtaining an access token from the response already exists. What we also need to add is a new code segment that will check if Google responded that we have an invalid refresh token. So, right before the if ([_responseJSON rangeOfString:@"access_token"].location != NSNotFound) line, add the following:

By calling the showWebviewForUserLogin method, we start the whole procedure over again.

13. Auxiliary Private Methods

Time to implement the rest of the auxiliary, private methods that we have already declared.

Step 1

Let’s begin with the -(NSString *)urlEncodeString:(NSString *)stringToURLEncode method, which is simply used to transform URL related strings to a URL-encoded form. When sending data over the web, not every character can exist in the URL. It should be replaced by other, special characters that are URL-friendly, and that’s exactly what the next method does:

As you can see, the CFURLCreateStringByAddingPercentEscapes function, which I would advise to read more about it, returns a CFStringRef type object, which is then converted to NSString when it’s returned. It’s not hard to understand the parameters this function accepts. Note that we provide a “list” of characters that should be replaced with percent characters. For example, the ! is converted to %21, the * to %2A, and so on. The last parameter relates to the desired encoding.

Step 2

We keep going with the next one:

Things are simple here. At first, the received data containing the access token information is stored in the accessTokenInfoDictionary mutable dictionary, which, in turn, is written to a file. Then, whether a refresh token exists is checked in the returned information. If found, it is extracted and saved to another file. Remember that we need to keep the refresh token separated from the access token file.

Step 3

Let’s see the loadAccessTokenInfo method now and then talk about it:

First of all, we check if the access token information file exists or not. If it exists, then it's loaded into the accessTokenInfoDictionary. If the file for some reason is not found, then the errorOccuredWithShortDescription:andErrorDetails: delegate method is called to inform the caller class.

Step 4

Next, let's see how to load the refresh token as well:

The approach here is the same as previously implemented. We check if the file with the refresh code exists, and if it does we load it into the refreshToken string. Otherwise, we report an error to the caller class through the delegate method.

Step 5

The next task is to check if the file with the access token information exists or not.

Step 6

Do exactly the same for the refresh token file.

Pretty simple, right?

Step 7

Let's see now how to check if an access token is valid or not. When talking for validity, we mean whether the access token has expired or not. Google returns the time that an access token may keep alive, along with the rest of the returned data. That time is expressed in seconds and it usually is 3,600 seconds or one hour. If an access token expires and we want to exchange data from a Google service, we simply need to refresh it in the background and obtain a new one.

Our strategy is going to be really simple. We will read the creation time of the file containing the access token info, as well as the time the access token should stay valid. If the time elapsed since the file creation is greater than the time to live, then a refresh is required, otherwise the access token is still valid. Let's see everything in action:

So, in case the access token should be refreshed we return YES, otherwise we return NO. Everything is self-explained, so I comment no further here.

Step 8

There is only one method that has been left out of these steps, the makeRequest. This method has nothing particular or special that I should point out. It exists just to avoid writing the same code every time we want to make NSURLRequest requests. So, as you will see right away, what we do is to empty the receivedData object by setting its length to zero and to make a new request.

14. NSURLConnection Additions

Step 1

There are a few more things that we should add inside the connectionDidFinishLoading: method to make this class more complete. Until now we have added support for dealing with responses regarding:

Invalid requests

Invalid grants (e.g. an expired refresh token)

Access token obtainment

What we should also add support for is the case of invalid credentials and for any other response that may contain the error word inside it. A response containing an Invalid credentials message arrives when an API is called and the access token is invalid. In our implementation, we always check if the access token is valid or not before doing any requests. However, this remains an edge case that we should predict. For any other general case that the response describes an error, we will call the errorInResponseWithBody delegate method. So, at the end of the connectionDidFinishLoading:, add the next code section:

If you look now at the connectionDidFinishLoading: method content, you'll see all the cases that we should take care of regarding the Google responses. For normal usage and for the purpose of this tutorial, almost nothing else needs to be added, except for one thing. The call to the responseFromServiceWasReceived:andResponseJSONAsData: delegate method. This method will be called every time that is retrieved a response about an API call that the caller class should handle it and it doesn't come under any other of the previous cases. Here it is:

Step 2

It would be useful (especially when debugging) to have the next method implemented as well:

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"%d", [http

Show more