iOS Authentication Tutorial - sample app

In Mobile Apps - Introduction to Development, we introduced various development options for mobile apps. In this tutorial, we get specific and address how to obtain an access token for native iOS application.

If you are new to iOS native app development, these resources will help you get started:

iOS: Dev Center
 
Basic Tutorial More Resources for iOS Developers

What this Tutorial Covers

This sample iOS Application demonstrates how to authenticate an OCLC user to obtain an access token.

A use case would be to allow a library patron to view their checked out items, place holds or renew materials on an iPhone or iPad.

Download the Code Sample

The OCLC Android Authentication Sample App is available from The OCLC Developer Network Github Repository.

git clone https://github.com/OCLC-Developer-Network/oclc-auth-ios-example.git

Configure the Authentication Parameters

To request or manage web service keys, use OCLC Service Configuration.

To learn more about authentication and access tokens, see this article on Mobile Flow from the OCLC Developer Network.

Before running the example, you must set the authentication parameters in the authentication.plist file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>authenticatingServerBaseUrl</key>
        <string>https://authn.sd00.worldcat.org/oauth2</string>
        <key>wskey</key>
        <string></string>
        <key>authenticatingInstitutionId</key>
        <string></string>
        <key>contextInstitutionId</key>
        <string></string>
        <key>redirectUrl</key>
        <string></string>
        <key>scopes</key>
        <string></string>
        <key>responseType</key>
        <string>token</string>
    </dict>
</plist>

 

The parameters are as follows:

  • wskey - the public key that identifies the client.
  • authenticatingInstitution - the institution that is responsible for authenticating the user.
  • contextInstitution - the institution's whose data the client is requesting access to.
  • redirectUrl - the url the authorization server should redirect the user to after login. For mobile flow, this should be a non-http reference unique to your application, such as oclcApp://user_agent_flow.
  • scopes - the service(s) that the client is requesting access to. Multiple scopes are separated by a space. Note that adding "refresh_token" to the list of scopes causes a refresh token to be issued.
  • responseType - should be "token".

If you try to run the app with blank parameters, you will get an error message. If the parameters are incorrect, the service will return an error message that is displayed on the screen.

Authentication User Experience

When we start our app or bring it forward from the background, the user may have not signed in, or the previous sign in may have expired. So we start the app with the sign in flow. The user will have three screens to interact with:

  1. Sign in - The user enters their UserID and Password.
  2. Service Authorization - In this case, the user has requested a token to access the WMS NCIP API, and is offered the opportunity to Allow this token to be used to make changes.
  3. Home Page - in this simple example, we display the successful authentication parameters, which could be used to interact with OCLC API's. In a real world app, a menu of functions or grid of icons would be presented to the user, and they would manipulate data with OCLC APIs using their authentication token.

The iOS User Experience for Authentication.

Authentication, Step by Step

Application Block Diagram

The application is organized into two main classes - a view controller and an authentication web view controller. For convenience the authentication parameters are stored in a properties list. The block diagram below illustrates the structure:

* Delegate Methods allow OCLC_AuthenticationUIWebView to communicate back to OCLC_ViewController so messages such as an activity spinner or authentication complete can be displayed on the screen for the user. There are three delegate methods defined:

  • authenticatedSuccess
  • displayActivityIndicator
  • hideActivityIndicator

Once an app is started for the first time on an iOS device, it will continue to run even if placed into the background. It will not stop running until the operating system shuts it off. This walk through starts with the app not yet running.

  1. The user selects the App's icon. The OCLC_ViewController class loads and, after the screen is loaded into the iOS device's active memory, the viewDidLoad method executes. We use this hook to do some start-up housekeeping:

    • Add a "Clear Cookies" button to the root view.
    • Add a "Sign In Again" button to the root view.
    • Add a token status label to the root view.
    • Add an activity spinner to the root view.
    • Initialize isAccessTokenValid flag to "NO"
    • Makes a request for an Access Token by calling the authenticate method.

    Remember, this method only executes when the app loads for the first time. It does not execute when the app is running, placed into the background so another app can run, and then recalled to the foreground. The user does not know, when they press the icon button, whether the app will be initializing or simply resuming. And the iOS operating system can kill an app's execution at any time to free up resources. So the viewDidLoad is used strictly for initialization.

  2. The authenticate method of the OCLC_ViewController class executes.
    A Note On iOS Delegate Methods

    At the top of the header file for OCLC_AuthenticationUIWebView.h, three delegate methods are defined. These are a list of methods that a subscribing class must implement.

    @protocol AuthenticationDelegate <NSObject> - (void)authenticatedSuccess: (BOOL) success result: (NSDictionary *) resuamp;lt; - (void)displayActivityIndicator; - (void)hideActivityIndicator; @end
    

    In this case, the OCLC_AuthenticationUIWebView class is handling the authentication process, and it needs to inform the root view controller class OCLC_ViewController when to turn on the spinner (while waiting for an authentication server response), turn off the spinner and of course when the authentication is complete (either successfully or not).

    So the OCLC_AuthenticationUIWebView class can call these delegate methods, and the OCLC_ViewController class will execute them. Because iOS is single threaded, these delegate methods do not execute in parallel, but rather control of the entire program goes to the delegate method and then returns to the calling method.

    • The authentication parameters are loaded from the authenticationList.plist file. Note that these parameters consist of:

      • WSKey
      • AuthenticatingInstitution
      • ContextInstitution
      • redirectUrl
      • scope

      If you hard code these parameters into your app, what does that mean? It means the app will be limited to the resources permitted by the wskey, which in turn is limited to specific authenticating and context institutions. If you were building an app that allowed sign in from 2 different institutions and resources to be accessed at 6 institutions, then you might remove authenticating and context institution ID's from the properties file and supply them from a UI selector or other logic.

      The redirectUrl is specific to your app, and must not be a http address for mobile applications. It serves as a "hook" to detect when a result is being returned with the access token attached, and we will watch for the redirectUrl during the flow to intercept it. An example redirectUrl might be univtoledo://patronapp

    • We extend UIWebView to create authenticationWebView which will handle the actual authorization. A UIWebView is simply a http browser without a user accessible url input field that we can embed in our application to handle http interaction between the user and the authentication servers. A critical piece of UIWebView functionality is the ability to intercept a redirect URL before it is sent to the server. We use this property to watch the traffic, looking for the redirectURL which will bear the Access Token and other parameters after a successful authentication.

    • We initialize the delegate object of our custom UIWebview to point back to the ViewController.

  3. After all this set up, we are ready to launch our custom web browser and execute the authentication flow. Program control moves from the OCLC_ViewController class to the OCLC_AuthenticationUIWebView class. There are three tasks to accomplish:

    1. If you'll recall, we loaded the authentication parameters from a property list file and we have passed them to the getToken method. So the first order of business is to build the token request URL. A typical request looks like this:

      https://authn.sd00.worldcat.org/oauth2/authorizeCode?
                  client_id={wskey}
                  &authenticatingInstitutionId={id}
                  &contextInstitutionId={id}
                  &redirect_uri={your custom redirect URI (non-http)}
                  &response_type=token&scope={your scopes}
              
      
    2. We need to enable cookies. The cookies for a UIWebView are stored on a "per app" basis. Enabling cookies means that if we authenticate after we've already authenticated, that we won't be asked our password again. We do this with:

      [myRequest setHTTPShouldHandleCookies:YES];
      

    3. Make the request!
      [self loadRequest:myRequest];
      
  4. Now that the request has been made, we are going to rely on three callback methods to keep us informed of the progress as the user interacts directly with the UIWebView to enter their password, and to authorize use of the specified scopes.

    Remember that the authentication flow will involve several redirects that are outside of our control. We are spectators as the user (hopefully) enters valid credentials.

    1. webViewDidStartLoad - fires when loading starts. Use to call the displayActivityIndicator delegate method so that the root view will display a beach ball.

    2. webViewDidFinishLoad -fires when a http request is received (good or bad). Used to turn fire hideActivityIndicator to turn off the spinning beach ball.

    3. shouldStartLoadWithRequest: - this function is critical. It executes before a http request is sent. This method watches for the redirectURL - and if it receives it, parses it for either the token and associated parameters, or for the error message if authentication went wrong. If the redirectURL is returned, we return NO to break the execution and prevent the redirectURL from being sent out as yet another http request. If the URL does not match the redirectURL, we simply return YES to allow the request to happen.

    Let's look at what a typical request looks like. To simplify the presentation, I replaced sensitive parameters such as wskeys and institution id's with "{}", but otherwise, the data is straight from XCode console:

    The authentication request is made.

    12:30:19.720:  https://authn.sd00.worldcat.org/oauth2/authorizeCode?
                       client_id={}
                       &authenticatingInstitutionId={}
                       &contextInstitutionId={}
                       &redirect_uri=ncipApp%3A%2F%2Fuser_agent_flow
                       &response_type=token&scope=WMS_NCIP
    
    12:30:20.019:  https://authn.sd00.worldcat.org/wskeyws/authorize.jsp
    
    12:30:20.432:  https://authn.sd00.worldcat.org/wayf/metaauth-ui/cmnd/protocol/samlpost
    
    12:30:21.754:  https://128807.authn.worldcat.org/login/manageduser-ui/cmnd/protocol/samlpost/oclc
    
    The user is asked to sign in with a userid and password.
    12:30:21.874:  https://128807.authn.worldcat.org/login/manageduser-ui/cmnd/useraction/login?
                       acsURL=https%3A%2F%2Fauthn.sd00.worldcat.org%2Fwayf%2Fmetaauth-ui%2Fcmnd%2Fprotocol%2Facs%2Fsaml2
                       &controllerMethod=samlpost
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    12:30:29.434:  https://128807.authn.worldcat.org/login/manageduser-ui/cmnd/useraction/samllogin
    
    The user is asked to authorize ("Allow" or "No Thanks") access to the service.
    12:30:29.649:  https://authn.sd00.worldcat.org/wayf/metaauth-ui/cmnd/protocol/acs/saml2
    
    12:30:30.208:  https://authn.sd00.worldcat.org/wskeyws/acs
    
    12:30:30.359:  https://authn.sd00.worldcat.org/wskeyws/authorize.jsp
    
    12:30:32.440:  https://authn.sd00.worldcat.org/wskeyws/HandleAuthorizeResponse
    
    The redirect URL is detected by shouldStartLoadWithRequest. Redirection is aborted.
    12:30:35.042:  ncipapp://user_agent_flow#access_token=tk_VL79XkEN8Pp7IVbcPydT7rMZECKh2s2oolAx
                       &principalID={}&principalIDNS={}
                       &context_institution_id={}
                       &token_type=bearer&expires_in=1199
                       &expires_at=2014-01-06%2017:50:34Z
            
    

    A close inspection of the redirectURL indicates a hashmark (#) instead of a question mark(?) delineates where our redirect URL ends and the parameters start. We can parse this string to get our token.

    If the user authenticates (valid userid and password), but there is some problem with the parameters passed such as a scope that is not assigned to the wskey submitted, then we would get back an error - something like this:

    12:30:35.042: ncipapp://user_agent_flow#error=access_denied&error_description=User+denied+access
    

    So you should always inspect the redirectURL for a error parameter.

    However, if the user enters an invalid UserId or Password, the authentication flow will terminate with a message for the user displayed in the UIWebView. No redirectURL will be sent. To handle this situation, the app should provide a button that allows the user to "Sign In Again".

More on returned parameters

There are currently two sets of parameters that can be returned with a redirectURL (in addition to the error parameter discussed above).

Access Token Request

An access token request is made by default. It returns these parameters

ncipapp://user_agent_flow#access_token=tk_VL79XkEN8Pp7IVbcPydT7rMZECKh2s2oolAx
    &principalID={}
    &principalIDNS={}
    &context_institution_id={}
    &token_type=bearer&expires_in=1199
    &expires_at=2014-01-06%2017:50:34Z

 

Note that in this example (and the one below), I used "ncipapp://user_agent_flow" as the redirect URL - yours would be different, but must not begin with "http://" for the mobile authentication flow to work.

Also note that the list of parameters begins with a hash mark instead of a question mark.

Access token requests are covered in Authentication and Authorization: User Agent or Mobile Flow

Refresh Token Request

A refresh token request is made by appending refresh_token to the list of space-separated scopes. It returns these parameters.

ncipapp://user_agent_flow#access_token=tk_GmVtYvffWZM7D721iO4mFiXI1ywlDWsTyFQU
    &principalID={}
    &principalIDNS={}
    &context_institution_id={}
    &token_type=bearer
    &expires_in=1199
    &expires_at=2014-01-13%2019:31:19Z
    &refresh_token=rt_dAbs7Ai3AYhr0bnbqw5LguTD0B7eW8kCwzh2
    &refresh_token_expires_in=604799
    &refresh_token_expires_at=2014-01-20%2019:11:19Z

 

Refresh tokens are covered in Authentication and Authorization: Refresh Tokens

Putting the Token to Work

This example shows how to authenticate a user against a specific service and institution(s), and receive an access token back - and that is as far as this example goes. The next step for you to code is to use the access token to make a request against an OCLC Web Service.

For example, when making a call to Lookup a User from the WMS NCIP OPAC service, you would need these parameters for the HTTP Request Headers.

Note - the requirement for principalID and principalIDNS is being deprecated - check the specific service's documentation to see if you must include them in addition to the token.

Authorization: bearer tk_U13DrzOHW8eep3jvwIpNX2rDcfuhvetNbrFm
principalID="{}"
principalIDNS="{}"

So long as the token remains valid, this will be sufficient authentication to access the service's resources.

In this case, the request is a post and contains an XML request body. You can learn more about WMS NCIP OPAC from WMS NCIP - OPAC Application Profile

Resources