Android 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 Android application.

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

Android: Developers
Basic Tutorial More Resources for Android Developers

What this Tutorial Covers

This sample Android 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-android-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.xml file.

<resources>
    <string name="authenticatingServerBaseUrl">https://authn.sd00.worldcat.org/oauth2</string>
    <string name="wskey"></string>
    <string name="authenticatingInstitutionId"></string>
    <string name="contextInstitutionId"></string>
    <string name="redirectUrl"></string>
    <string name="scopes"></string>
    <string name="responseType">token</string>
</resources>

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.

Running the Sample Application

From the eclipse Run menu, select Run Configurations. The Launch Action should specify "Launch Default Activity". From the Target Tab, you need to select a target device for the simulator. I used a Galaxy Nexus 7, but you can choose from a variety of devices.

Select the file MainActivity.java and press the run button on the top toolbar.

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 simple display the successful authentication parameters, which could be used to interact with OCLC APIs. 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 Android 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:

* Callback Methods allow AuthenticatingWebView.java to communicate back to MainActivity.java so a progress dialog can be activated or inactivated, or the results of the authentication can be displayed. There are three callback methods defined in the interface file AuthenticatingWebViewCallbackMethods.java:

  • displayResults()
  • startProgressDialog()
  • stopProgressDialog()

Once an app is started for the first time on an Android 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 MainActivity.java class loads and, after the screen is loaded into the Android device's active memory, the onCreate() method executes. We use this hook to do some start-up housekeeping:

    • Load the Display as described in the activity_main.xml file. Some display elements are initially set to invisible, and are made visible by MainActivity.java as appropriate during program execution. Display elements include:
      1. A webView for user interaction during authentication
      2. A textView to display token status and time remaining until invalid.
      3. A Clear Cookies Button
      4. A Sign In Again Button
      5. A textView to display authentication results.
    • Enable cookies.

    • Build the request URL by loading the authentication parameters from authentication.xml. 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

    • Add a token status label to the root view.
    • Add an activity spinner to the root view.
    • Initialize isAccessTokenValid flag to "NO"
    • Make a request for an Access Token by instantiating AuthenticatingWebView and calling the makeRequest() 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 Android operating system can kill an app's execution at any time to free up resources. So the onCreate() method is used strictly for initialization.

  2. The makeRequest() method of the AuthenticatingWebView class executes.
    A Note On Android Callback Methods

    To permit the AuthenticatingWebView class to communicate status back to the MainActivity.java class, the MainActivity class implements the AuthenticatingWebViewCallbackMethods interface, which defines these methods:

    public interface AuthenticatingWebViewCallbackMethods {
        /**
         * Method is called when it is time to display the progress spinner, for
         * example when loading on the web view.
         */
        void startProgressDialog();
    
        /**
         * Method is called when it is time to hide the progress spinner
         */
        void stopProgressDialog();
    
        /**
         * Method is called when authentication is complete
         *
         * @param authorizationReturnParameters The params returned with the token
         */
        void displayResults(HashMap
         
           
            
           authorizationReturnParameters);
    }
                            
         
           

    When we inspect MainActivity, we see that these callback methods are implemented. They can then be called from the AuthenticatingWebView class.

    • The makeRequest method clears the webView display and passes the URL request to it.
  3. 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. The method onPageStarted() - fires when loading starts. Use to call the displayActivityIndicator delegate method so that the root view will display a beachball.

    2. The method onPageFinished -fires when a http request is recieved (good or bad). Used to turn fire hideActivityIndicator to turn off the spinning beachball.

    3. The method shouldOverrideUrlLoading 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 false 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 true 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 "{}":

    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 and 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