iOS Authentication Token URL

Server-side Authentication

You will also want to configure a Social Login application.

If you want to access any of the extra features available in the Janrain Engage API, or if you want complete server-side authentication, implement a token URL as follows:

  1. Create a server-side HTTP or HTTPS endpoint (preferably HTTPS). This will be your auth_info token URL, and mobile devices running your mobile app will POST an Engage auth_info token to this endpoint, in exchange for an access token for your web service.
  2. From the new endpoint, extract the token. It is POSTed in the token parameter.
  3. Call auth_info. Supply:
    1. The token just received.
    2. Your application’s 40-character Engage API key.
  4. Process the profile data returned from auth_info and log your user into your web application. (The unique and secure key you should use to identify the user is the identifier field of the profile node). Create and return access tokens or session cookies in your endpoint’s response as necessary. Your mobile app will receive that response.

For example, in Ruby on Rails you might rely on the ActionController session and the cookie that it sets like this:

# The following helper class is from the Engage sample code found at
# https://github.com/janrain/Janrain-Sample-Code
ENGAGE = Rpx::RpxHelper.new("your_api_key_here",
                            "http://rpxnow.com",
                            "your_engage_app_realm_here") # e.g. mytestapp

# This is the Engage auth_info token URL -- the endpoint which spawns
# new mobile user sessions.
def mobileEngageSignIn
   auth_info = ENGAGE.auth_info(params[:token])

   identifier = auth_info['identifier']

   user = User.find_or_create_by_engage_identifier(identifier)
   # do other stuff, like populate the User record with the auth_info

   session[:user_id] = user.id
end

If you’re using the Rails ActionController session, set the cookie expiration to an appropriate value for a mobile device:

# This initializer block is found in app/config/environment.rb
Rails::Initializer.run do |config|
  config.action_controller.session[:session_expires] = 10.years.from_now
end

Then, make sure that you save the cookie in your mobile app. For example:

org.apache.http.cookie.Cookie[] mSessionCookies;

public void jrAuthenticationDidReachTokenUrl(String tokenUrl,
                                             HttpResponseHeaders responseHeaders,
                                             String tokenUrlPayload,
                                             String provider) {
    mSessionCookies = responseHeaders.getCookies();
}

From your new auth_info token URL you can also access other Engage features. For example, you could call get_contacts and use the returned contact list to find other users of your mobile app that this user may know. Note: Some features are limited to Pro, Plus, or Enterprise customers only.

To configure the library with your token URL, pass it to initInstance when initializing the library:

private static final String ENGAGE_APP_ID = "";
private static final String ENGAGE_TOKEN_URL = "";
private JREngage mEngage;
private JREngageDelegate mEngageDelegate;

...

mEngage = JREngage.initInstance(this, engageAppId, engageTokenUrl, mEngageDelegate);

Alternatively, you can change the token URL at any time using the setTokenUrl method:

JREngage mEngage;

...

mEngage.setTokenUrl(newTokenUrl);

You may configure the library with a null or empty token URL, and this authentication step will be skipped.

Whether or not the library posts the token to the token URL, your Android application must not contain your Engage API key.

iOS Engage Custom Provider Guide

This guide describes the process of configuring custom OpenID and custom SAML providers into the Engage library. This guide assumes you have already completed either the iOS Engage-only Integration Guide or the JUMP for iOS Integration Guide.

Guide Overview

  1. Gather configuration details.
  2. Build a custom-providers configuration dictionary.
  3. Initialize the library with the dictionary.
  4. Begin authentication by calling one of the show...Dialog methods.

Gather Configuration Details

For each custom provider you want to configure, gather the following configuration details:

  • Provider ID – A short string that will be used to refer to the custom provider. For example, the provider ID for Yahoo! is yahoo. This is used only in the context of the iOS app, and can be any arbitrary value you choose.
  • Friendly name – A string representing the user-facing name of the provider. For example, the friendly name for Yahoo! is “Yahoo!”.

Custom Open ID

In addition to the configuration details mentioned previously you will need:

  • The OpenID identifier of your custom OpenID provider.
  • Optionally, a custom opx_blob parameter for use with Janrain Identity Services’ OpenID providers.

Custom SAML

In addition to the configuration details mentioned previously you will need:

  • The name of the SAML implementation in Engage for your custom SAML provider.

Build the Custom-Providers Configuration Dictionary

Construct an NSDictionary similar to this example. The field names in the inner dictionaries are important (that is, the field for friendly name must be “friendly_name”):

NSDictionary *customProviders =
    @{
        @"my_custom_saml_provider": // this is the "provider ID".
            @{
                @"friendly_name": @"Example Custom SAML Provider",
                @"saml_provider": @"the_name_of_the_engage_implementation_of_the_saml_provider"
            },
        @"my_custom_openid_provider":
            @{
                @"friendly_name": @"Example Custom OpenID Provider",
                @"openid_identifier": @"https://my-custom-openid-provider.com/example-openid-identifier",
                @"opx_blob": @"some_blob_for_opx" // This is an optional field
            },
        // You can define more custom SAML or custom OpenID providers below. They just need to have different
        // "provider IDs"
    };

Icons

You can add a 30x30 provider icon for you custom providers by naming the icon icon_your-provider-id-here_30x30.png and including the icon file in your iOS app’s Resources project group.

Initialize the Library with the Dictionary

The configuration of the custom providers varies slightly between Engage-only and complete JUMP integrations.

JUMP

Call:

+[JRCapture setEngageAppId:captureDomain:captureClientId:captureLocale:captureFlowName:captureFormName:captureTraditionalSignInType:customIdentityProviders:]

… passing in the custom provider configuration dictionary you defined for the customIdentityProviders: parameter.

Engage-Only

Initialize the library as usual, then call +[JREngage setCustomProviders:], passing in the custom provider configuration dictionary you defined for the customProviders parameter.

Begin Authentication

Start authentication as you normally would (or as described in the integration guide). Your custom providers will appear in the stock authentication provider list UI. You can skip the stock provider-list UI and start authentication directly on any provider, including your custom providers:

  • For whole-JUMP integrations use: +[JRCapture startEngageSignInDialogOnProvider:forDelegate:]
  • For Engage-only integrations use: +[JREngage showAuthenticationDialogForProvider:]

Note: There are also other variants of those methods that accept a provider ID parameter.

iOS Engage-only Integration Guide

This guide describes integrating Engage-only into your iOS App. For a description of JUMP platform integration steps see JUMP for iOS Integration Guide.

Guide Overview

  1. Gather configuration details.
  2. Add the library to your Xcode project.
  3. Initialize the library with your Engage application’s application ID, your web server’s token URL, and your delegate object (which conforms to the JREngageSigninDelegate and/or the JREngageSharingDelegate protocols).
  4. Begin authentication or sharing by calling one of the show...Dialog methods.
  5. Receive your token URL’s response in -authenticationDidReachTokenUrl:withResponse:andPayload:forProvider:.

Gather Configuration Details

Configure Identity Providers on the Engage Dashboard

  1. Make sure your desired set of social identity providers is configured in the Engage Dashboard.
  2. Sign in to Engage and configure the providers.

Note: Configuring the providers themselves is a separate step from configuring which providers are enabled for the Engage library.

Configure the Providers Used in the iOS Library

While signed in to the Engage dashboard:

  1. Activate the Engage for iOS Configuration Wizard (from the drop-down menu, select Deployment > Engage for iOS).
  2. Follow the wizard and configure the providers to use for authentication and social sharing from the iOS library.

Retrieve your Engage Application ID

You will also need your 20-character Application ID from the Engage Dashboard. Click the Home link in the Engage Dashboard. Your app ID is located in the right-most column, towards the bottom of the column under the Application Info header.

Add the Engage Library to the Xcode Project

  1. Follow the JUMP for iOS Xcode Project Setup Guide, but skip the step “Generating the Capture User Model”.
  2. Remove the JRCapture project group from your project.

Choose an Engage Delegate Class and Initialize the Library

  1. Select the class you will use to receive callbacks from the Engage library. This is called your Engage delegate. The delegate should be persistent (will not be dealloced during the course of your app’s lifetime) and it should be a singleton. Your app’s AppDelegate is a good choice to start with.

  2. In the interface of your chosen Engage delegate class, import the Engage header #import "JREngage.h" and conform to the JREngageSigninDelegate and JREngageSharingDelegate protocols:

    @interface AppDelegate : UIResponder <UIApplicationDelegate, JREngageSigninDelegate>
    
  3. In your delegate’s implementation, during its initialization (or from elsewhere in your app’s initialization), call the JREngage initialization method (for example, from from your AppDelegate’s -application:didFinishLaunchingWithOptions:):

    [JREngage setEngageAppId:@"<your app id>" tokenUrl:@"<your_token_url>" andDelegate:yourEngageDelegate];
    
  4. Stub out these two delegate message implementations in your delegate:

    (void)authenticationDidReachTokenUrl:(NSString *)tokenUrl withResponse:(NSURLResponse *)response
                                andPayload:(NSData *)tokenUrlPayload forProvider:(NSString *)provider
    {
        NSLog(@"%@", [response description]);
    }
    
    (void)authenticationDidSucceedForUser:(NSDictionary *)authInfo forProvider:(NSString *)provider
    {
        NSLog(@"%@", [authInfo description]);
    }
    
    

Social Sign-In

An Engage authentication is only meaningful in the context of authenticating your mobile app to something. If you are unsure of what your users should be signing in to, Janrain Capture may be a suitable choice.

To start authentication send the showAuthenticationDialog message to the JREngage class:

[JREngage showAuthenticationDialog];

You will receive your authentication token URL’s response in the authenticationDidReachTokenUrl:... message. When received, you will have access to the body of the response (as well as the headers) that frequently contain session cookies used to coordinate the app’s session with your web server. Parsing your authentication token URL’s response for session-establishing information, or retrieving session cookies from the header, is your app’s responsibility.

For guidance implementing your web server’s authentication token URL, see Server-side Authentication.

Social Sharing

If you want to share an activity:

  1. Create an instance of the JRActivityObject and populate the activity object’s fields:

    JRActivityObject *activity = [JRActivityObject activityObjectWithAction:@"added JREngage to her iPhone application!" andUrl:@"http://janrain.com"];[/sourcecode]
    
  2. Pass the activity to the showSharingDialogWithActivity: message:

    [JREngage showSharingDialogWithActivity:activity];
    

Your user may choose to sign in with additional social providers in order to share. If the user does, your delegate will receive the authenticationDidSucceedForUser:forProvider: and authenticationDidReachTokenUrl:withResponse:andPayload:forProvider: messages. If you don’t want new authentications posted to your token URL, you can remove the token URL with the updateTokenUrl: message.

Additionally, as your users shares their activity on the different providers, you will receive sharingDidSucceedForActivity:forProvider: messages on your JREngageSharingDelegate delegate. Finally, the JREngageSharingDelegate delegate will receive a sharingDidComplete message once the user finishes sharing. If the user cancels sharing before the activity was posted to any provider, the delegate will receive the sharingDidNotComplete message.

Good to Know

The first time your application uses JREngage on any device, the library contacts the Engage servers to retrieve your application’s configuration information. After downloading, the library caches this information. The library updates the cache only when the information changes (for example, when you add or remove a provider). The library checks for updates after it initializes.

While you can initialize the JREngage library immediately before you call one of the show... methods, your users may encounter our loading screen while the library contacts the Engage servers.

JUMP for iOS Integration Guide

This guide describes integrating the Janrain User Management Platform into your iOS app. This includes the Capture user registration system. For Engage-only (that is, social authentication-only) integrations, see the Engage-only Integration Guide.

Warning: You must have a flow configured with your Capture instance to use the Capture library.

JUMP SDK Features

  • Engage social sign-in (includes OpenID and many OAuth identity providers–for example, Google, Facebook, and so on).
  • Sign-in to Capture accounts
    • Either via Engage social sign-in or via traditional username/password sign-in.
    • Including the Capture “merge account flow” (that links two social accounts by verified email address at sign-in time).
  • Register new Capture accounts
    • Traditional accounts (for example, authenticated via password).
    • Social accounts (with pre-populated registration forms).
    • “Thin” social registration–Automatic account creation for social sign-in users without a registration form.
  • Capture account record updates
  • Session refreshing

Guide Overview

Basic use flow:

  1. Gather your configuration details
  2. Add the JUMP for iOS SDK to your Xcode project.
  3. Initialize the library
  4. Start a sign-in
  5. Modify the profile
  6. Send record updates
  7. Persist the local user object

SimpleCaptureDemo

There is a JUMP SDK demo in Samples/SimpleCaptureDemo. The demo includes a default configuration in Sample/SimpleCaptureDemo/assets/janrain-config-default.plist. To customize the demo configuration, copy that file to janrain-config.plist and edit the contents.

The demo shows:

  • Registration
  • Sign-in
  • Record updates
  • Session refreshing

Gather your Configuration Details

  1. Sign in to your Engage dashboard (https://rpxnow.com).
    1. Configure the social providers you want to use for authentication (select the menu item Deployment > Engage for iOS).
    2. Retrieve your 20-character Engage application ID from the Engage dashboard (in the right column of the Engage Dashboard Home page).
  2. Ask your deployment engineer or account manager for your Capture domain.
  3. Create a new Capture API client for your mobile app:

    1. Sign in to the Capture dashboard and provision a new API client for your mobile app (https://janraincapture.com). (Copy down the new API client’s client ID, you will need this.)
    2. Use the dashboard to add the login_client feature to your new API client. Warning: login_client is mutually exclusive with all other API client features, which means only login clients can be used to sign in users, and only non-login clients can perform client_id and client_secret authenticated Capture API calls. This means that you cannot use the owner client as a login client.
    3. Use the setAccessSchema endpoint to set the subset of the schema you want your mobile app to update. You must use the write_with_token schema type.

      Warning: If you do set the write_with_token access schema for your API client to include the attributes your client will write to in its write access schema, you will receive missing attribute errors when attempting to update attributes.

      Warning: Do not use the write schema type with login clients–instead, use write_with_token.

      Warning: This cannot be done from the dashboard, it must be done with the API.

      It is assumed that you are integrating the JUMP SDK into your app in order to update attributes of the user’s record on Capture. In order to update attributes the write_with_token access schema must be set for your app’s API client.

      Because record updates from the iOS SDK use the entity API, they are not suitable for security-sensitive attributes (such as the user’s email address, password, and display name). You should restrict the write access schema to those attributes you want the user to have direct control over (for example, app data such as “favorites,” usage history, and user-generated content.

  4. Discover your flow settings. Ask your deployment engineer for:

    • The name of the Capture flow you should use.
    • The name of the flow’s traditional sign-in form.
    • The name of the flow’s social registration form.
    • The name of the flow’s traditional registration form.
    • The name of the locale in the flow your app should use (the commonly-used value for US English is en-US).
  5. Determine whether your app should use “thin” or “two-step” social registration.

  6. Determine the name of the traditional sign-in key attribute (for example, email or username).

Warning: You must create a new API client with the correct login_client feature to use the JUMP for iOS SDK.

Xcode Project Setup

Follow the steps in the Xcode Project Setup Guide.

Import the Library and Declare a JRCaptureUser Property

In your application, determine where you want to manage the authenticated Capture user object. You want to implement your Capture library interface code in an object that won’t go away, such as the AppDelegate or a singleton object that manages your application’s state model.

  1. In the chosen class’s header, import the Capture library header:

    #import "JRCapture.h"
    #import "JRCaptureConfig.h"
    
  2. Modify your class’s interface declaration to declare conformation to the protocol (all of the messages of the protocol are optional). For example, start your AppDelegate’s interface declaration like this:

    @interface AppDelegate : UIResponder <UIApplicationDelegate, JRCaptureDelegate>
    
  3. Add a JRCaptureUser * property to your class’s interface declaration:

    @property (nonatomic) JRCaptureUser *captureUser;
    
  4. In your class’s implementation, synthesize that property:

    @synthesize captureUser;
    

Initialize the Library

To configure the library, pass your configuration settings to the initializer method. Call this as soon as possible during your app’s lifecycle so the network configuration call has time to complete before the library is used.

Copy and paste this block into -[AppDelegate application:didFinishLaunchingWithOptions:] to get started:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ... Your existing initialization logic here

    JRCaptureConfig *config = [JRCaptureConfig emptyCaptureConfig];
    config.engageAppId = @"your_engage_app_id";
    config.captureDomain = @"your_capture_ui_base_url";
    config.captureClientId = @"your_capture_client_id";
    config.captureLocale = @"en-US"; // e.g.
    config.captureFlowName = nil; // e.g.
    config.captureFlowVersion = nil; // e.g.
    config.captureSignInFormName = @"signinForm";
    config.captureTraditionalSignInType = JRTraditionalSignInEmailPassword;
    config.enableThinRegistration = YES;
    config.customProviders = nil;
    config.captureTraditionalRegistrationFormName = @"registrationForm"; // e.g.
    config.captureSocialRegistrationFormName = @"socialRegistrationForm"; // e.g.
    config.captureAppId = @"your_capture_app_id";
    config.forgottenPasswordFormName = @"forgotPasswordForm"; // e.g.
    config.editProfileFormName = @"editProfileForm";

    [JRCapture setCaptureConfig:config];
}

Start the User Sign-In Flow

To start the authentication and sign-in flow, send the startEngageSignInForDelegate: message to the JRCapture class. For example, you could call this method when your app’s sign-in button is pressed:

@interface MyAppSignInViewController () <JRCaptureDelegate>
@end

// ...

@implementation MyAppSignInViewController

// ...

- (IBAction)signInButtonTouchUpInside:(id)sender
{
    [JRCapture startEngageSignInForDelegate:self];
}

This starts the Engage user authentication flow, the result of which is used to sign in to Capture. Once a user is signed in, the library instantiates a user model object (an instance of JRCaptureUser).

The JRCaptureDelegate protocol defines a set of (optional) messages your Capture delegate can respond to. As the flow proceeds, a series of delegate messages will be sent to your delegate.

First, your delegate will receive engageAuthenticationDidSucceedForUser:forProvider: when Engage authentication is complete. At this point, the library will close the authentication dialog and headlessly complete sign-in to Capture. This message contains limited data that can be used to update UI while your app waits for Capture to complete authentication.

- (void)engageAuthenticationDidSucceedForUser:(NSDictionary *)engageAuthInfo
                                  forProvider:(NSString *)provider
{
    self.currentDisplayName = [self getDisplayNameFromProfile:engageAuthInfo];

    // Update the UI to show that authentication is completing...
    [self showCompletingSigninVisualAffordance]; // E.g. a UIActivityIndicator

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}

Once the authentication token reaches Capture, Capture automatically adds the profile data to the Capture record.

Finish the User Sign-In Flow

Once the the user record is retrieved from Capture, the captureSignInDidSucceedForUser:status: message is sent to your delegate. This message delivers the JRCaptureUser instance, and also the state of the record.

@interface MyAppSignInViewController () <JRCaptureDelegate>
@end

// ...

@implementation MyAppSignInViewController

// ...

- (void)captureSignInDidSucceedForUser:(JRCaptureUser *)newCaptureUser
                                status:(JRCaptureRecordStatus)captureRecordStatus
{
    // Retain a reference to the user object
    myAppDelegate.captureUser = newCaptureUser;

    // User records can come back with one of two states
    if (captureRecordStatus == JRCaptureRecordNewlyCreated)
    {
        // The user has not signed in to this Capture instance before and a new record
        // has been automatically created. This is called a "thin registration"

        // You may wish to collect additional data from the user and add it
        // to the user's record, e.g. an avatar image URL, T.O.S. acceptance, etc.
    }
    else if (captureRecordStatus == JRCaptureRecordExists)
    {
        // The user had a pre-existing Capture user record
    }
}

There are two possible values for captureRecordStatus:

  • JRCaptureRecordExists indicates that the user had an existing Capture record and that record has been retrieved. Your application should update its state to reflect that the user is signed in.

  • JRCaptureRecordNewlyCreated indicates this is a new user and a new Capture record has been automatically created (this is called “thin registration”). Because this is a new user, your application may want to collect additional profile information and push that information back to Capture.

Optionally, your delegate can receive captureDidSucceedWithCode:. When the sign-in has succeeded, this is called with a Capture OAuth authorization code that can be used by a server-side application (such as the Capture Drupal Plugin) to retrieve an access token.

Traditional Sign-in and Social Sign-in

The Capture part of the SDK supports both social sign-in via Engage (for example, Facebook) as well as traditional sign-in (that is, username and password or email and password sign-in). There are four main ways to start sign-in:

  • +[JRCapture startEngageSignInDialogForDelegate:]–Starts the Engage social sign-in process for all currently-configured social sign-in providers, displaying a list of them initially, and guiding the user through the authentication.
  • +[JRCapture startEngageSignInDialogOnProvider:withCustomInterfaceOverrides:mergeToken:forDelegate:]–Starts the Engage social sign-in process beginning directly with the specified social sign-in identity provider (skipping the list of configured social sign-in providers).
  • +[JRCapture startEngageSignInDialogWithConventionalSignin:forDelegate:]–Start the Engage social sign-in process for all currently-configured social sign-in providers, preceding the list with a traditional sign-in form.
  • +[JRCapture startCaptureTraditionalSigninForUser:withPassword:withSignInType:mergeToken:forDelegate:]–Starts the traditional sign-in flow headlessly.

The first two methods start social sign-in only (either by presenting a list of configured providers, or by starting the sign-in flow directly on a configured provider). The last method performs a headless traditional sign-in–useful if your host app wants to present its own traditional sign-in UI. The third method combines social sign-in with a stock traditional sign-in UI.

The merge token parameters are used in the second part of the Merge Account Flow, described below.

Handling the Merge Account Sign-in Flow

Sometimes a user has created a record with one mechanism of sign-in (for example, a traditional username and password record) and will later attempt to sign in through a different mechanism (for example, with Facebook).

When this happens the sign-in cannot succeed because there is no Capture record associated with the social sign-in identity and the email address from the identity is already in use.

Before being able to sign in with the social identity, the user must merge the identity into their existing record (this is called the Merge Account Flow).

The merge is achieved at the conclusion of a second sign-in flow authenticated by the record’s existing associated identity. The second sign-in is initiated upon the failure of the first sign-in flow, and also includes a merge token that Capture uses to merge the identity from the first (failed) sign-in into the record.

Capture SDK Event Sequence for the Merge Account Flow

  1. User attempts to sign in with a social identity (“identity F”).
  2. Capture sign-in fails because there is an existing Capture record connected to “identity G” that shares some constrained attributes with “identity F” (for example, the two identities have the same email address).
  3. The -[JRCaptureSigninDelegate captureSignInDidFailWithError:] delegate message is sent with an error representing this state. You can identify this state via the -[NSError isJRMergeFlowError]-class category message.
  4. The host application (your mobile app) notifies the user of the conflict and advises the user to merge the accounts.
  5. The user elects to take action.
  6. The merge sign-in is started by invoking either +[JRCapture startEngageSignInDialogOnProvider:withCustomInterfaceOverrides:mergeToken:forDelegate:] or +[JRCapture startCaptureConventionalSigninForUser:withPassword:withSigninType:mergeToken:forDelegate:] (depending on the existing identity provider for the record).

    The existing identity provider of the record is retrieved with the -[NSError JRMergeFlowExistingProvider] message, and the merge token with the -[NSError JRMergeToken] message.

Example
@interface MyAppSignInViewController () <JRCaptureDelegate>
@end

// ...

@implementation MyAppSignInViewController

// ...

- (void)captureSignInDidFailWithError:(NSError *)error
{
    if ([error code] == JRCaptureErrorGenericBadPassword)
    {
        [self handleBadPasswordError:error]; // Advises the user to try again.
    }
    else if ([error isJRMergeFlowError])
    {
        [self handleMergeFlowError:error];
    }
}

- (void)handleMergeFlowError:(NSError *)error
{
    NSString *existingAccountProvider = [error JRMergeFlowExistingProvider];
    void (^mergeAlertCompletion)(UIAlertView *, BOOL, NSInteger) =
            ^(UIAlertView *alertView, BOOL cancelled, NSInteger buttonIndex)
            {
                if (cancelled) return;

                if ([existingAccountProvider isEqualToString:@"capture"]){ // Traditional sign-in required
                    [self performTradAuthWithMergeToken:[error JRMergeToken]];
                }
                // Optional if you are implementing Native Provider SDK's
                // Please read the Native Authentication Guide before implenting these.
                /*
                else if ([existingAccountProvider isEqualToString:@"facebook"]){
                    [self startNativeFacebook:[error JRMergeToken]];
                }else if ([existingAccountProvider isEqualToString:@"googleplus"]){
                    self.isMergingAccount = YES;
                    self.activeMergeToken =[error JRMergeToken];
                    [self startNativeGoogleplus];
                }else if ([existingAccountProvider isEqualToString:@"twitter"]){
                    [self startNativeTwitter:[error JRMergeToken]];
                */
                }else{
                    // Social sign-in required:

                    [JRCapture startEngageSignInDialogOnProvider:existingAccountProvider
                                    withCustomInterfaceOverrides:self.customUi
                                                      mergeToken:[error JRMergeToken]
                                                      forDelegate:self.captureDelegate];
                }
            };

    [self showMergeAlertDialog:existingAccountProvider mergeAlertCompletion:mergeAlertCompletion];

}

- (void)handleTradMerge:(NSError *)error
{
    void (^signInCompletion)(UIAlertView *, BOOL, NSInteger) =
            ^(UIAlertView *alertView_, BOOL cancelled_, NSInteger buttonIndex_)
            {
                if (cancelled_) return;
                NSString *user = [[alertView_ textFieldAtIndex:0] text];
                NSString *password = [[alertView_ textFieldAtIndex:1] text];
                [JRCapture startCaptureConventionalSigninForUser:user withPassword:password
                                                  withSigninType:JRTraditionalSignInEmailPassword
                                                      mergeToken:[error JRMergeToken]
                                                      forDelegate:self];
            };

    [[[AlertViewWithBlocks alloc] initWithTitle:@"Sign in" message:nil completion:signInCompletion
                                          style:UIAlertViewStyleLoginAndPasswordInput
                              cancelButtonTitle:@"Cancel"
                              otherButtonTitles:@"Sign-in", nil] show];
}

Note: This example makes use of the AlertViewWithBlocks subclass of UIAlertView (that provides an interface to UIAlertView with a block handler, as opposed to a delegate object handler). See the SimpleCaptureDemo project in the Samples directory of the SDK for source code.

This example:

  • Checks for the merge-flow error
  • Prompts the user to merge
  • Starts authentication

Note: The existing provider of the merge flow can be Capture itself. This happens when the merge failure was a conflict with an existing record created with traditional sign-in. This case is handled in the handleTradMerge: method.

Performing Account Linking Flow

There are times when a user wants to link another social identity provider to the existing Capture account. This flow enables a user to link other social identity provider accounts to the current Capture account.

+[JRCapture startAccountLinkingSignInDialogForDelegate:forAccountLinking:withRedirectUri:] starts the social sign-in process for all currently-configured social sign-in providers, displays a list of them initially, and guides the user through the authentication. Once the authentication is completed, this new account is linked to the existing Capture account.

Parameters

  • JRCaptureDelegate–A Capture delegate object.
  • forAccountLinking–A bool value to indicate whether to perform account linking or not. Set to YES to start account linking.
  • withRedirectUri–A URL that is used if and only if the flow is set to trigger an email after linking accounts successfully.

You can configure email triggering during the Capture account setup process.

Delegates

  • -(void)linkNewAccountDidFailWithError:(NSError *)error–The delegate is fired with an error when the account linking fails.

  • -(void)linkNewAccountDidSucceed–The delegate is fired after the account linking process succeeds.

Example

Let’s call this on the click of a button for Account Linking:

[JRCapture startAccountLinkingSignInDialogForDelegate:self.captureDelegate
                                    forAccountLinking:YES
                                      withRedirectUri:@"http://your-domain-custom-redirect-url-page.html"]

Note: This should be called when the user has already signed in to a Capture application.

A user can have multiple accounts linked to the same Capture account. To unlink an account associated with an existing Capture account, use this flow. This flow will unlink one account at a time, in a successful execution.

Note: This should be called when the user has already signed in to a Capture application.

  • [JRCaptureData getLinkedProfiles]–Use this method to fetch the list of linked accounts after a successful sign-in. The linked profile array consists of a dictionary of linked profiles. This is stored in the JRCaptureData object. Each dictionary object has the following keys:

    • verifiedEmail
    • identifier–Use this value for unlinking an account.
  • +[JRcapture startAccountUnlinking:(id<JRCaptureDelegate>)delegate forProfileIdentifier:(NSString *)identifier–This unlinks the account (identified by identifier) from the existing Capture account. Pass any identifier value being retrieved from the [JRCaptureData getLinkedProfiles] array. The JRCapture will trigger accountUnlinkingDidFailWithError and accountUnlinkingDidSucceed delegates.

Delegates

  • -(void)accountUnlinkingDidFailWithError:(NSError *)error–This delegate is fired when the account unlinking process fails.

  • -(void)accountUnlinkingDidSucceed–This delegate is fired after a successful account unlinking flow.

Example

Let’s call this on the click of a button for account unlinking.

Note: Call this when the user has already signed in to a Capture application.

// store the Linked accounts into your array aobject from JRCaptureData object.
NSArray *linkedProfiles = [JRCaptureData getLinkedProfiles];

if([linkedProfiles count]) {
  NSString *selectedProfile = [[linkedProfiles objectAtIndex:0] valueForKey:@"identifier"];

  // pass the selected  identifier to the unlinking method.
  [JRCapture startAccountUnlinking:self.captureDelegate forProfileIdentifier:selectedProfile];
}

Making Changes in a Capture User Record

Capture Schema Basics

Capture user records are defined by the Capture schema, which defines the attributes of the record. An attribute is either a primitive value (a number, a string, a date, or a similar type), an object, or a plural.

Primitive attribute values are the actual data that make up your user record. For example, they are your user’s identifier, or their email address, or their birthday.

Your user record consists of objects and plurals. For example, in the default Capture schema, the user’s name is represented by an object with six primitive values (strings) used to contain the different parts of the name. The six values are:

  • familyName
  • formatted
  • givenName
  • honorificPrefix
  • honorificSuffix
  • middleName

Objects can contain primitive values, sub-objects, or plurals, and these attributes are defined in the schema.

Plurals contain collections of objects. Each element in a plural is an object or another plural. Every element in a plural has the same set of attributes that are defined in the schema. Think of a plural as an object that may have zero or more instances.

Generating your Capture user model produces Objective-C classes for all your objects and non-string-plural plural elements. For example, you will have a JRName class that contains NSString properties for the six attributes previously discussed.

Internally, Capture user record updates occur through one of two mechanisms: updating and replacing. Both updating and replacing are limited in scope to part of the record, depending on the object from which they are called. Broadly speaking, parts of the record that are limited to objects can be updated, but to change the plural elements in a plural you must replace the plural. For example, JRName (the user’s name) is an object and can be updated if the user changes part of their name, but JRInterests (a plural of strings holding the user’s interests) must be replaced if the user adds or removes an interest.

Updating User Profiles

Conform to the JRCaptureDelegate protocol in your class:

@interface MyCaptureEditProfileController : UIViewController <JRCaptureDelegate>

Update the properties of your JRCaptureUser that corresponds to the fields of the editProfileForm in your flow. For example, givenName, familyName, birthdate, aboutMe, and so on.

Call +[JRCapture updateProfileForUser:delegate] to update the user’s profile.

The delegate method updateUserProfileDidSucceed is called upon a successful update. If the update fails for any reason, updateUserProfileDidFailWithError: is called instead.

Updating Record Entities (Non-Plurals)

Conform to the JRCaptureObjectDelegate protocol in your class:

@interface MyCaptureUserManager : NSObject <JRCaptureObjectDelegate>

Update the object’s non-plural properties, and send the object the updateOnCaptureForDelegate:context: message. For example:

appDelegate.captureUser.aboutMe = @"Hello. My name is Inigo Montoya.";
[appDelegate.captureUser updateOnCaptureForDelegate:self context:nil];

Note: Context arguments are used across most of the asynchronous Capture methods to facilitate correlation of the response messages with the calling code. Using the context is entirely optional. You can use any object that conforms to <NSObject>.

You may respond to updateDidSucceedForObject:context: for notification of success:

- (void)updateDidSucceedForObject:(JRCaptureObject *)object context:(NSObject *)context
{
    // Successful update
}

Similarly, updateDidFailForObject:withError:context: is sent on failure. See Capture Errors in the API documentation for possible errors.

You can send the updateOnCaptureForDelegate:context: message to the top-level object (an instance of JRCaptureUser), or a sub-object of that object.

Warning: When you update an object, the update does not affect plurals inside of that object.

Working with Plurals

Overview

The Mobile SDK has support for replacing existing plurals when properly configured.

Make sure you have an up-to-date Registration User Model.

By default, any entity API calls other than the base entity call can not be used with a Mobile or JavaScript implementation. The Mobile and JavaScript implementations are designed to not have API client secrets embedded in them. Additionally, Mobile SDK and JavaScript implementations are designed to use only API clients with the login_client feature.

When an end user authenticates through an API client with the login_client feature, the access token that it returned is scoped to only permit read-only access to the user’s profile data. The access token can not be used to make any entity calls that would modify the user’s profile data (for example, entity.update, entity.replace). All edits to the user’s profile data must be submitted through the Janrain Registration server using either the JavaScript implementation or the Mobile SDK (which uses the OAuth API endpoints).

Access Schemas

Note: Access schemas are leveraged by several components in the Janrain Registration system. Consult with Janrain before modifying an access schema.

The Registration API client filtering of read and write access is implemented through a feature called access schemas. Each Registration API client can have only the following access types:

  • read
  • write
  • write_with_token

The write access schema will always be used when an API client ID and secret combination is provided to any of the editing entity API calls. The write_with_token access schema will always be used when a valid access token is provided to any of the editing entity API calls.

By default, an API client with the login_client feature will have a read access schema that provides full read access to the entire user profile, and write and write_with_token access schemas that provide no write access to the user profile. Note: Reserved attributes (id, uuid, created, lastUpdated) are automatically included in the access schema but are not accessible through the entity calls.

In order for the Mobile SDKs or JavaScript implementations to leverage the editing entity API calls, you must create a write_with_token access schema and use the access_token parameter instead of the client_id and client_secret parameters with the API calls.

Access Schema API Calls:

To add or remove the elements of a plural, send the replace_ArrayName_ArrayOnCaptureForDelegate:context: message to the parent object of the plural, where ArrayName is the name of the plural attribute.

For example, if you have a schema with a plural attribute named photos, the user model generator generates a method named replacePhotosArrayOnCaptureForDelegate:context:. In this case, ArrayName is Photos.

Once the values in the plural element attribute have been updated in the local instance of the user record model, Capture can be updated by calling replace_ArrayName_ArrayOnCaptureForDelegate:context:. For example:

// Make a new photos plural element:
JRPhotosElement *newPhoto = [[JRPhotosElement alloc] init];
newPhoto.value = @"http://janrain.com/wp-content/uploads/drupal/janrain-logo.png";

// Make a new array with the new element added:
NSMutableArray *newPhotos = [NSMutableArray  arrayWithArray:captureUser.photos];
[newPhotos addObject:newPhoto];

// Assign the new array to the photos plural property:
captureUser.photos = newPhotos;

// ... And update Capture:
[captureUser replacePhotosArrayOnCaptureForDelegate:self context:nil];

Warning: The NSArray properties used to model plurals are copy-on-set. This means that to modify the array you must create a new mutable array with the existing array, then modify the mutable array, then assign the mutable array to the property. (Because the property is copy-on-set, further modifications to the copied array will not change the property.) See the previous code sample for an example of this technique.

Persisting the Capture User Record

When your application terminates, you should save your active user record to local storage. For example, from your UIApplicationDelegate:

#define cJRCaptureUser @"jr_capture_user"

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Store the Capture user record for use when your app restarts;
    // JRCaptureUser objects conform to NSCoding so you can serialize them with the
    // rest of your app state
    NSUserDefaults *myPreferences = [NSUserDefaults standardUserDefaults];
    [myPreferences setObject:[NSKeyedArchiver archivedDataWithRootObject:captureUser]
                      forKey:cJRCaptureUser];
}

Likewise, load the saved user record state when your application launches. For example, from your UIApplicationDelegate:

- (BOOL)          application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSUserDefaults *myPreferences = [NSUserDefaults standardUserDefaults];
    NSData *encodedUser = [myPreferences objectForKey:cJRCaptureUser];
    self.captureUser = [NSKeyedUnarchiver unarchiveObjectWithData:encodedUser];
}

Warning: While your application is responsible for saving and restoring the user record, the Capture library will automatically save and restore the session token.

Refreshing the User’s Access Token

Call +[JRCapture refreshAccessTokenForDelegate:context:] to refresh the signed-in user’s access token. Access tokens last for one hour. They may be refreshed after expiration. The underlying refreshing system lasts “a long time”.

Next: Registration

Once you have sign-in and record updates working, see the JUMP User Registration Guide for a guide to new-user registration.

Troubleshooting

Failed Sign-in Due to Client Permissions

Sign-ins fail with an error message indicating that the client doesn’t have the necessary permissions.

Ensure that the API client ID you are using is for an API client with the login_client API client feature. To configure this, use the /clients/set_features endpoint. To get the set of configured API client features, use the /clients/list endpoint.

Attribute Does Not Exist

code: 223 error: unknown_attribute description: attribute does not exist: /your_attr_name

Use /entityType.setAccessSchema to add write access to this attribute on your native API client.

Undefined Symbol _CATransform3DConcat

Undefined symbols for architecture i386: "_CATransform3DConcat", referenced from:

Add the QuartzCore framework to the build target for the project.

Undefined Symbol _OBJC_CLASS_$_MFMailComposeViewController

Undefined symbols for architecture i386: "_OBJC_CLASS_$_MFMailComposeViewController", referenced from:

Add the MessageUI framework to the build target for the project (set it to Optional).

iOS Native Authentication Guide

This guide describes the process of integrating with native iOS authentication systems. The Social Sign-in library has historically supported authentication by means of a UIWebView running a traditional web OAuth flow. Support is now introduced for authentication by means of native identity provider libraries.

Supported Providers

  • Facebook
  • Google+
  • Twitter

Native Authentication for Janrain Mobile SDK version 4.0 (or newer)

Warning: There are potentially breaking changes to the Janrain Mobile SDK with version 4.0. All dependencies on third-party SDKs and libraries around native Social Provider support (Google+, Facebook, and Twitter) have been removed.

The Mobile SDK no longer integrates third-party Social Provider SDKs or libraries. The SimpleCaptureDemo app has been upgraded to demonstrate how to retrieve a native provider’s oAuth access token using the current (at the time of the SDK release) native provider’s tools in as close a format to the native provider’s sample code on their website. You will now retrieve the native provider’s oAuth access token using their preferred method and initiate the Janrain authentication process using startEngageSignInWithNativeProviderToken:provider:withToken:andTokenSecret:withCustomInterfaceOverrides:mergeToken:forDelegate:.

Guide Overview

  1. Configure the native authentication framework for the providers you want to support (Google+, Facebook, or Twitter).
  2. Give the user the option to sign in with a native provider or through a UIWebview dialog for non-native providers.
  3. If the user selects to log in with a native provider, initiate the native provider’s SDK and retrieve a properly-scoped oAuth access token (and token secret for Twitter).
  4. Pass the native provider’s oAuth access token to the Janrain SDK where it will be posted to the Social Login server for verification and a Social Login access token will be returned.

Facebook

As of SDK release 4.0, the following Facebook SDK implementation steps were implemented in the SimpleCaptureDemo sample application in order to retrieve the Facebook oAuth access token from the iOS device:

  1. Download the Facebook SDK for iOS from this link: https://developers.facebook.com/docs/ios
  2. Follow all of the steps on this page except for Step 2 (Create a Facebook App): https://developers.facebook.com/docs/ios/getting-started/
    In order for the Janrain Social Login server to validate the provided Facebook oAuth token, the token must be provisioned from the same Facebook application that is configured for the Janrain Social Login application. In most cases, just add an iOS App Settings configuration to the existing Facebook app.
  3. Use this page as a starting point for implementing native Facebook login: https://developers.facebook.com/docs/facebook-login/ios/v2.4
  4. Make sure the permissions requested in the logInWithReadPermissions method include the required permissions. In most cases, these permissions must mirror the Facebook app permissions configuration of the Engage Social Login application that is configured in the Janrain Social Login dashboard.
  5. Refer to the RootViewControoler.m file for an example of how this was done with the SimpleCaptureDemo application.
  6. Once you have retrieved the oAuth access token from the Facebook SDK, you can initiate the Janrain authentication process with startEngageSignInWithNativeProviderToken:provider:withToken:andTokenSecret:withCustomInterfaceOverrides:mergeToken:forDelegate:.

Google+

As of SDK release 4.0, the following Google SDK implementation steps were implemented in the SimpleCaptureDemo sample application in order to retrieve the Google+ oAuth access token from the iOS device:

  1. Download the Google+ SDK from this link: https://developers.google.com/+/mobile/ios/getting-started
  2. Follow all of the steps on this page that involve the XCode project configuration and Google+ app configuration: https://developers.google.com/+/mobile/ios/getting-started. In order for the Janrain Social Login server to validate the provided Google+ oAuth token, the token must be provisioned from the same Google+ application that is configured for the Janrain Social Login application. In most cases, simply add an iOS App Client ID configuration to the existing Google+ app.
  3. In the case of the SimpleCaptureDemo application, the integration steps were implemented in the RootViewControoler files with minimal changes from the examples provided by Google at this link: https://developers.google.com/identity/sign-in/ios/sign-in
  4. Make sure that the Scopes requested by the GPPSignIn singleton include the required scopes. In most cases, these scopes need to mirror the Google+ app permissions configuration of the Engage Social Login application that is configured in the Janrain Social Login dashboard.
  5. Refer to the RootViewControoler.m file for an example of how this was done with the SimpleCaptureDemo application.
  6. Once you have retrieved the oAuth access token from the Google+ SDK, you can initiate the Janrain authentication process with startEngageSignInWithNativeProviderToken:provider:withToken:andTokenSecret:withCustomInterfaceOverrides:mergeToken:forDelegate:.

Twitter

As of SDK release 4.0, the following Twitter Fabric, TwitterKit SDK implementation steps were implemented in the SimpleCaptureDemo sample application in order to retrieve the Twitter oAuth access token from the iOS device:

  1. Download the Fabric SDK from this link: https://get.fabric.io/ (and include TwitterKit).
  2. Configure your Twitter App: http://docs.fabric.io/ios/twitter/configure-twitter-app.html. In order for the Janrain Social Login server to validate the provided Twitter oAuth token, the token must be provisioned from the same Twitter application that is configured for the Janrain Social Login application. In most cases, simply add an iOS App Client ID configuration to the existing Twitter App.
  3. In the case of the SimpleCaptureDemo application, the integration steps were implemented in the RootViewControoler files with minimal changes from the examples provided by Twitter at this link: http://docs.fabric.io/ios/twitter/authentication.html.

    Note: In most default cases Twitter will not return an email address for an end user. This may cause account merging or linking issues if your Registration user experience relies heavily on merged social profiles. This use case is typically addressed by forcing Twitter account holders to use the “Account Linking” functionality of the SDK. Customers may choose to work with Twitter to get their application white-listed so it will attempt to return an email address from a user profile. However, email addresses are not “required” for Twitter accounts, subsequently there is still no guarantee that an email address will be returned.

  4. Refer to the RootViewControoler.m file for an example of how this was done with the SimpleCaptureDemo application.

  5. Once you have retrieved the oAuth access token and token secret from the TwitterKit SDK you can initiate the Janrain authentication process with startEngageSignInWithNativeProviderToken:provider:withToken:andTokenSecret:withCustomInterfaceOverrides:mergeToken:forDelegate:.

DEPRECATED: Native Authentication Implementation for Janrain Mobile SDK Versions prior to Version 4.0

Prior versions (before version 4.0) of the Janrain Mobile SDK attempted to use reflection to call the native provider SDKs and retrieve the oAuth access token. This presented a maintenance and compatibility issue with the Janrain SDK only able to support specific versions of the native provider SDKs. The following documentation will be removed in a subsequent release but is preserved for customers using older versions of the Janrain Mobile SDK.

  • Native Authentication is supported by the library, and is compatible with both Social Sign-in only and User Registration deployments.
  • At this time, native authentication is available for authentication only, and not for social identity resource authorization (for example, sharing).
  • The SDK is not currently able to request the same scopes that are configured in the Engage dashboard when using Native Authentication. This will be available in a future release. For now, Facebook requests basic_info and Google+ requests plus.login.

Overview

  1. Configure the native authentication framework.
  2. Start User Registration sign-in or Social Sign-in authentication.
  3. The library will delegate the authentication to the native authentication framework.
  4. The library delegate message will fire when native authentication completes.

Facebook

Configure the Native Authentication Framework

Follow the Facebook iOS SDK integration instructions. For native Facebook authentication to work via Social Sign-in, both Janrain and the Facebook iOS SDK must be configured to use the same Facebook application. Make sure to use the same Facebook app ID as is configured in your application’s dashboard.

Ensure that the Facebook Sources Are Linked

Add the -ObjC flag to the app target’s build settings: https://developer.apple.com/library/mac/qa/qa1490/_index.html

Handle the Facebook Login Callback

When authenticating, the Facebook SDK will pass control to the Facebook iOS app or to Facebook in a mobile browser. Your app will need to handle the callback to finish signing in. Add the following to your application delegate:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
    return [JREngage application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}

It is possible that the redirect back to your app may be interrupted. If that happens, the Janrain iOS SDK can do some cleanup and put your application in a position to restart the authentication. Add the following to your application delegate:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [JREngage applicationDidBecomeActive:application];
}

Begin Sign-in or Authentication

Start authentication or sign-in as normal. If the Facebook iOS SDK is compiled into your app, it will be used to perform all Facebook authentication.

Signing Out

Following Facebook’s documentation, we’ll use closeAndClearTokenInformation to close the in-memory Facebook session.

In your view controller, import the Facebook SDK:

#import <FacebookSDK/FacebookSDK.h>

Call closeAndClearTokenInformation when your sign-out button is pressed. For example, in SimpleCaptureDemo, we add the following to the signOutCurrentUser method of the RootViewController:

- (void)signOutCurrentUser
{
    ...

    // Sign out of the Facebook SDK
    [FBSession.activeSession closeAndClearTokenInformation];
}

Note: This does not revoke the application’s access to Facebook. If a user has a Facebook account set up in their iOS device’s Settings app, it will continue to be used to sign in without asking to be reauthorized.

Google+

Configure the Native Authentication Framework

Follow the Google+ platform Getting Started guide. For native Google+ authentication to work via Social Sign-in, both Janrain and the Google+ iOS SDK must be configured to use the same Google+ project in the Google Cloud Console.

Configure the Janrain SDK

If you are using Janrain’s user registration, add your iOS Google+ client ID to your JRCaptureConfig instance:

config.googlePlusClientId = @"YOUR_CLIENT_ID";

If you are using Social Sign-in only, after your call to +[JREngage setEngageAppId:tokenUrl:andDelegate:], set your Google+ client ID:

[JREngage setGooglePlusClientId:@"YOUR_CLIENT_ID"

Handle the Google+ Login Callback

When authenticating, the Google+ SDK may pass control to Google+ in a mobile browser. Your app will need to handle the callback to finish signing in. Add the following to your application delegate:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
    return [JREngage application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}

It is possible that the redirect back to your app may be interrupted. If that happens, the Janrain iOS SDK can do some cleanup and put your application in a position to restart the authentication. Add the following to your application delegate:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [JREngage applicationDidBecomeActive:application];
}

Begin Sign-in or Authentication

Start authentication or sign-in as normal. If the Google+ iOS SDK is compiled into your app, it will be used to perform all Google+ authentication.

Signing Out and Disconnecting from the Google+ SDK

Follow the directions in https://developers.google.com/+/mobile/ios/sign-in under Sign out the user and Revoking access tokens and Disconnecting the app.

Twitter

Configure the Janrain SDK

Make sure that you have Accounts.framework and Social.framework linked to your target.

If you are using Janrain’s user registration, add your Twitter consumer key and consumer secret to your JRCaptureConfig instance:

config.twitterConsumerKey = @"YOUR_CONSUMER_KEY";
config.twitterConsumerSecret = @"YOUR_CONSUMER_SECRET";

Or, if you are using Social Sign-in only, after your call to +[JREngage setEngageAppId:tokenUrl:andDelegate:], set your Twitter consumer key and consumer secret:

[JREngage setTwitterConsumerKey:@”YOUR_CONSUMER_KEY
                      andSecret:@”YOUR_CONSUMER_SECRET”];

Make sure that your Twitter consumer key and consumer secret match what you have configured in the Engage dashboard.

When a user has not given your application permission to access the Twitter accounts, the -[engageSignInDidFailWithError:] method of your JRCaptureDelegate or the -[authenticationDidFailWithError:forProvider:] method of your JREngageSigninDelegate will be called with an error. You can handle the error by checking to see if its code is JRAuthenticationNoAccessToTwitterAccountsError. For example:

#import "JREngageError.h"
...
    - (void)engageSignInDidFailWithError:(NSError *)error
    {
        DLog(@"error: %@", [error description]);
        if (error.code == JRAuthenticationNoAccessToTwitterAccountsError) {
            NSString *message = @"We weren't granted access to your accounts. "
                            @"Please change your Twitter settings.";
            UIAlertView *alertView = [[UIAlertView alloc]
                initWithTitle:@"Twitter Error"
                          message:message
                         delegate:nil
                cancelButtonTitle:@"Dismiss"
                otherButtonTitles:nil];
            [alertView show];
        }
    }

Begin Sign-in or Authentication

Begin sign-in as usual and it will follow the flow diagram (shown below).

Note: The iOS 6 simulator does not behave correctly with +[SLComposeViewController isAvailableForServiceType:], which is used to determine if there is at least one Twitter account in the first set of the diagram.

Twitter Flow Diagram

Janrain iOS SDK Upgrade Guide

This guide describes the steps required to upgrade from different versions of the library.

Generalized Upgrade Process

A less desirable but more reliable (and more general) upgrade strategy:

  1. Remove existing Janrain project groups.
  2. Remove generated Capture user model project groups.
  3. Follow the process described in the JUMP Integration Guide.

Upgrading from any version to v4.0 or greater

Warning: There are potentially breaking changes to the Janrain Mobile SDK with version 4.0. All dependencies on third-party SDKs and libraries around native Social Provider support (Google+, Facebook, and Twitter) have been removed.

The Mobile SDK no longer integrates third-party SDKs or libraries. The SimpleCaptureDemo app has been upgraded to demonstrate how to retrieve a native provider’s oAuth access token using the current (at the time of the SDK release) native provider’s tools in as close a format to the native provider’s sample code on their website. You will now retrieve the native provider’s oAuth access token using their preferred method and initiate the Janrain authentication process using startEngageSignInWithNativeProviderToken:provider:withToken:andTokenSecret:withCustomInterfaceOverrides:mergeToken:forDelegate:.

Refer to the Native Authentication Guide for full details on how to implement native authentication with the above changes.

Several provider images and icons were updated in this release, so refresh the files in the Resources folder.

Upgrading from any Version to v3.7 or Greater

The Janrain iOS SDK now requires Automatic Reference Counting (ARC). Follow the generalized upgrade process but do NOT add the -fno-objc-arc compiler flag to the Janrain sources. If your project does not use ARC, be sure to set the Objective-C Automatic Reference Counting build setting to YES and add the -fno-objc-arc compiler flag to any of your sources that do not support ARC.

Solutions

  • No known class method for selector ‘startForgottenPasswordRecoveryForField:recoverUri:delegate:’

    The recoverUri parameter has been removed from this method. Use the password_recover_url Capture dashboard setting instead and call the method [JRCapture startForgottenPasswordRecoveryForField:delegate:].

Upgrading from any Version to v3.6 or Greater

  1. Ensure that the Accounts and Social frameworks have been added to your project.
  2. Ensure that your deployment target is at least iOS 6.

Solutions for Upgrading from v2.5.2-v3.1.4 to v3.4.0

  • ‘JSONKit.h’ file not found

    Remove #import "JSONKit.h, as it is no longer required for JUMP.

  • no visible @interface for ‘NSDictionary’ declares the selector ‘JSONString’

    Import JRJsonUtils.h and change JSONString to JR_jsonString.

  • no visible @interface for ‘NSArray’ declares the selector ‘JSONString’

    Import JRJsonUtils.h and change JSONString to JR_jsonString.

  • no visible @interface for ‘NSString’ declares the selector ‘objectFromJSONString’

    Import JRJsonUtils.h and change objectFromJSONString to JR_objectFromJSONString.

Solutions for Upgrading v3.1.4 to v3.4.0

  • no visible @interface for ‘NSError’ declares the selector ‘JRMergeFlowExistingProvider’

    Import JREngageError.h.

  • no visible @interface for ‘NSError’ declares the selector ‘JRMergeToken’

    Import JREngageError.h.

  • no visible @interface for ‘NSError’ declares the selector ‘isJRMergeFlowError’

    Import JREngageError.h.

  • use of undeclared identifier ‘JRCaptureErrorGenericBadPassword’

    Import JREngageError.h.

Solutions for upgrading v2.5.2 to v3.4.0

  • no visible @interface for ‘JRCaptureUser’ declares the selector ‘createOnCaptureForDelegate:context:’

    Use +[JRCapture registerNewUser:socialRegistrationToken:forDelegate:] instead.

  • Use of undeclared identifier ‘JRCaptureErrorGenericBadPassword’

    Import JREngageError.h.

  • use of undeclared identifier ‘JRCaptureRecordMissingRequiredFields’

    JRCaptureRecordMissingRequiredFields has been removed.

  • no known class method for selector ‘setEngageAppId:captureApidDomain:captureUIDomain:clientId:andEntityTypeName:’

    Use +[JRCapture +setCaptureConfig:] instead. For example, if you had:

    [JRCapture setEngageAppId:engageAppId captureApidDomain:captureApidDomain
        captureUIDomain:captureUIDomain clientId:captureClientId andEntityTypeName:nil];
    

    Then do the following instead:

    JRCaptureConfig *config = [JRCaptureConfig emptyCaptureConfig];
    config.engageAppId = engageAppId;
    config.captureDomain = captureDomain;
    config.captureClientId = captureClientId;
    config.captureLocale = @"en-US";
    [JRCapture setCaptureConfig:config];
    

Upgrading from v2.2.0-v2.3.x to v3.4.0

  1. Delete the JREngage group from Xcode.
  2. Get the latest version of the SDK from GitHub: git clone https://github.com/janrain/jump.ios.git.
  3. Make sure that the Project Navigator pane is showing.
  4. Open Finder and navigate to the location where you cloned the jump.ios repository. Drag the Janrain folder into your Xcode project’s Project Navigator and drop it below the root project node.

    Warning: Do not drag the jump.ios folder into your project–instead, drag in the Janrain folder.

  5. In the dialog, do not select Copy items is not destination group’s folder (if needed). Ensure that the Create groups for any added folders radio button is selected, and that the Add to targets check box is selected for you application’s target.

  6. v2.2.0 and v2.3.0 did support Capture, so you need to remove the JRCapture project group from the Janrain project group.

  7. You must also add the QuartzCore and MessageUI frameworks to your project. As the MessageUI framework is not available on all iOS devices and versions, you must designate the framework as optional.

  8. Ensure that your Deployment Target is iOS 5.0 or higher.

Solutions for Upgrading from v2.2.0-v2.3.x to v3.4.0

  • Delegate methods are not being called

    Delegate method names are no longer prepended with jr. For example:

    • jrEngageDialogDidFailToShowWithError: has been replaced with engageDialogDidFailToShowWithError:.
    • jrAuthenticationDidSucceedForUser:forProvider has been replaced with authenticationDidSucceedForUser:forProvider:.
    • jrAuthenticationDidReachTokenUrl:withPayload:forProvider: has been replaced with authenticationDidReachTokenUrl:withResponse:andPayload:forProvider:.
    • jrAuthenticationDidReachTokenUrl:withResponse:andPayload:forProvider: has been replaced with authenticationDidReachTokenUrl:withResponse:andPayload:forProvider:.
    • jrAuthenticationDidNotComplete has been replaced with authenticationDidNotComplete.
    • jrAuthenticationDidFailWithError:forProvider: has been replaced with authenticationDidFailWithError:forProvider:.
    • jrAuthenticationCallToTokenUrl:didFailWithError:forProvider: has been replaced with authenticationCallToTokenUrl:didFailWithError:forProvider:.
  • cannot find protocol declaration for ‘JREngageDelegate’

    Change <JREngageDelegate> to <JREngageSigninDelegate>.

  • Use of undeclared identifier ‘JRDialogShowingError’

    Import JREngageError.h.

  • class method ‘+jrEngage’ not found (return type defaults to ‘id’)

    This method has been removed. Some of the instance methods that you might be trying to use have been replaced with class methods.

  • Instance method ‘-authenticationDidCancel’ not found (return type defaults to ‘id’)

    Use the class method +[JREngage cancelAuthentication] instead.

  • instance method ‘-cancelPublishing’ not found (return type defaults to ‘id’)

    Use the class method +[JREngage cancelSharing] instead.

Solutions for Upgrading v2.3.x to v3.4.0

  • Instance method ‘-showAuthenticationDialogWithCustomInterfaceOverrides:’ not found (return type defaults to ‘id’)

    Use +[JREngage showAuthenticationDialogWithCustomInterfaceOverrides:] instead.

Solutions for Upgrading v2.2.0 to v3.4.0

  • Instance method ‘-setCustomNavigationController:’ not found (return type defaults to ‘id’)

    Instance method ‘-setCustomInterfaceDefaults:’ not found (return type defaults to ‘id’)

    Use +[JREngage showAuthenticationDialogWithCustomInterfaceOverrides:] instead. For example, if you had:

    NSDictionary *myCustomInterface = @{
            kJRProviderTableHeaderView : embeddedTable.view,
            kJRProviderTableSectionHeaderTitleString : @"Sign in with a social provider"
    };
    [myJREngageInstance setCustomNavigationController:myNavigationController]
    [customInterface addEntriesFromDictionary:myCustomInterface];
    [myJREngageInstance setCustomInterfaceDefaults:customInterface];
    [myJREngageInstance showAuthenticationDialog];
    

    Then do the following:

    NSDictionary *myCustomInterface = @{
            kJRProviderTableHeaderView : embeddedTable.view,
            kJRProviderTableSectionHeaderTitleString : @"Sign in with a social provider",
            kJRApplicationNavigationController : myNavigationController
    };
    [JREngage showAuthenticationDialogWithCustomInterfaceOverrides:myCustomInterface];
    

Upgrading from 3.0.x to 3.1

The signature to the JRCapture initialization method added a new parameter to its selector, customIdentityProviders:, which describes custom identity providers with which to configure the library. See the iOS Engage Custom Provider Guide for more details.

Upgrading from 3.1.x to 3.2

The signature to the JRCapture initialization method added several new parameters to its selector. See the selector in JRCapture.h which begins setEngageAppId: for the current list of parameters.

JUMP for iOS User Registration Guide

This guide describes use of the user registration feature in the JUMP SDK. This guide is a follow-on to the JUMP Integration Guide, which describes the fundamentals of the integration process.

Registration Types

There are three types of user registration:

  • Traditional registration. This is registration as traditionally implemented. The user fills out a form, and the fields of the form are submitted via a JUMP platform API, which registers the user.
  • Thin social registration. This is automatic registration based on social identities. It is used only in the context of an authentication with a social identity. No form is presented to the user. The user’s social identity is used to populate the fields of a new user record if one does not already exist for their social identity identifier URL.
  • Two-step social registration. This is a registration form with pre-populated values from the user’s social identity. The first step is “the user authenticates with a social identity, but no user record is found so a pre-populated form is returned to the user”. The second step is “the user submits the registration form”.

Thin Registration

Thin registration is enabled or disabled at the time you configure the Capture library via the captureEnableThinRegistration: part of the configuration selector. Pass YES to enable thin registration. No further configuration is required. When thin registration is possible, it will be performed by Capture automatically and the user will be signed in simultaneously.

Thin Registration Requirements

For thin registration to succeed, all Capture schema constraints and rules must be fulfillable with the social profile (see /entityType.setAttributeConstraints and /entityType.rules). If a constraint or rule cannot be met, thin registration will not occur and the JUMP for iOS library will return error code 3310 JRCaptureApidErrorRecordNotFound. For example, if there is the schema constraint required on the /email attribute of your schema, users attempting to sign in with Twitter (which does not profile an email address in its social profiles) will not be able to thin-register.

Detecting Thin Registrations

If thin registration is enabled and succeeds for a user, the captureAuthenticationDidSucceedForUser:... message is sent to the JRCaptureSigninDelegate designated to receive responses from the sign-in process (that is, the delegate parameter passed to one of the startEngageSigninDialogForDelegate: or its variants, or to startCaptureConventionalSigninForUser.

When captureAuthenticationDidSucceedForUser:... is received by your JRCaptureSigninDelegate the status: parameter will be JRCaptureRecordNewlyCreated.

Traditional Registration

To perform traditional registration, first instantiate an empty Capture user object: JRCaptureUser *registeringUser = [JRCaptureUser captureUser].

Then, present a registration form of your own creation to the user and allow the user to fill in values. There should be a field in your form for each of the fields in your traditional registration form in your flow. (You can look in your flow directly, or ask your deployment engineer for a list of these fields.)

For example, for the default Capture schema and the standard user registration flow, display five text fields (one each) for the following attributes in the default Capture schema:

  • /email
  • /displayName
  • /firstName
  • /lastName
  • /password

When the user submits the form, copy the text field values into the corresponding properties in the Capture user model object created above. Once the user object is populated with values, call +[JRCapture registerNewUser:socialRegistrationToken:forDelegate:]. Use nil for the social registration token.

Upon completion, a corresponding delegate message will be sent to the delegate (either registerUserDidFailWithError: or registerUserDidSucceed:).

Handling Form Validation Failures

Capture performs server-side form validation on all forms. If there is a validation error, your delegate will receive a failure message. The error received in that message can be inspected, and form validation errors can be differentiated from other (for example, networking) errors and presented to the user.

To detect a form validation error use -[NSError isJRFormValidationError]. A validation error, once detected, can be further inspected by using -[JRCaptureError JRValidationFailureMessages]. This selector returns a dictionary of form-field-names to array-of-localized-error-messages-for-that-field. For example, it might return a dictionary like:

@{
    @"email" : @[@"Invalid email address"],
    @"password" : @[@"Passwords must be six or more characters."]
@}

The localized validation failure messages will be localized in accordance with the locale used to configure the JUMP library.

“Two-Step” Social Registration

Two-step social registration is the composition of a failed social sign-in and a registration. It is started via the social sign-in API first, with a follow-on call to the registration API when the sign-in fails.

To perform a social registration, first the user is run through the social sign-in API. Inspect the error received in captureAuthenticationDidFailWithError: with -[NSError isJRTwoStepRegFlowError]. If YES, the sign-in error can be recovered by performing a social registration. The error received will also provide a pre-populated user object which should be used to pre-populate the social registration form.

Implementation

Two-step social registration is performed similarly to traditional registration, as described above, but with the addition of a social registration token in the registerNewUser:socialRegistrationToken:forDelegate: message.

The social registration token is retrieved from the error received in captureAuthenticationDidFailWithError: with the -[NSError JRSocialRegistrationToken] selector, and the pre-populated user object can be retrieved with -[NSError JRPreregistrationRecord].

With the pre-populated user record, display a form with fields pre-populated by the properties of the pre-registration record and pass the social registration token in with the registration message.

Social registration form validation errors can be handled in the same way as traditional registration form validation errors.

Forgotten Passwords

When a user submits an incorrect email address or password in a traditional registration sign-in from the provider list, the user is given the option to create a new password. The UIAlertView that informs the user of the failed sign-in has a button to begin the forgotten password flow. Once the user clicks Forgot Password, another UIAlertView is presented asking the user to confirm their email address. If the user clicks Send, an API call is made to Capture that triggers an email with instructions on how the user can reset the password.

To trigger the forgotten password flow directly, call +[JRCapture startForgottenPasswordRecoveryForEmailAddress:recoverUri:delegate].

Example

In Samples/SimpleCaptureDemo, see the RootViewController for an example of the JRCaptureSigninDelegate, and see CaptureDynamicForm for an example of a traditional registration form. CaptureProfileViewController is an example of the social registration form (although currently only the email address attribute/field is hooked up).

Xcode Project Setup Guide

This guide explains how to integrate the JUMP SDK into an existing Xcode project.

Get the Library

If you haven’t already, clone the JUMP for iOS library from GitHub: git clone git://github.com/janrain/jump.ios.git.

Important: If you are upgrading from an earlier version of the library, see the Janrain iOS SDK Upgrade Guide.

Add the Library to Your Xcode Project

  1. Open your project in Xcode.
  2. Make sure that the Project Navigator pane is showing (View > Navigators > Show Project Navigator).
  3. Open the Finder and navigate to the location where you cloned the repository. Drag the Janrain folder into your Xcode project’s Project Navigator pane, and drop it below the root project node. Warning: Do not drag the jump.ios folder into your project; instead, drag the Janrain folder in.
  4. In the dialog, do not select the Copy items into destination group’s folder (if needed) box. Ensure that the Create groups for any added folders radio button is selected and the Add to targets check box is selected for your application’s targets.
  5. Click Finish.
  6. Warning: If you are doing a social-sign-in-only (that is, Engage-only) integration, you must now remove the JRCapture project group from the Janrain project group.
  7. You must also add the Security, QuartzCore, and MessageUI frameworks to your project. As the MessageUI framework is not available on all iOS devices and versions, you must designate the framework as “optional”. As of JUMP iOS v4.0, you must also add the Accounts and Social frameworks.
  8. Ensure that your deployment target is at least iOS 7.0 and not higher than iOS 8.4 (this is required as of JUMP iOS v4.0). In order to maintain the broadest range of iOS version compatibility, the SDK still implements some features that are deprecated in iOS 9.0 and higher. Setting a deployment target of iOS9 or higher will prevent the SDK from successful compilation.

Frameworks:

  • Security - This framework is used to store session tokens in the device’s security framework so that they are stored securely.
  • QuartCore - This framework is used for animations when running on the iPad.
  • MessageUI - This framework is used to integrate with the iOS device’s native SMS and email capabilities, to allow your end users to share your content via email or SMS.

Localization

The JUMP SDK uses NSLocalizedString for all user-facing strings. String values are loaded from the ios_internal/Janrain/JREngage/Resources/en.lproj folder in the Localizable.strings file. Only English strings are provided in the SDK. You can, however, provide your own translations:

  1. Create a folder in the ios_internal/Janrain/JREngage/Resources/ folder named for the language you are localizing to (for instance, for a French translation, create fr.lproj) and in that folder add a new file named Localizable.strings.
  2. Copy the contents of ios_internal/Janrain/JREngage/Resources/en.lproj/Localizable.strings to your newly-created fr.lproj/Localizable.strings file.
  3. Strings are formatted as “key”:“value” pairs where the key is always the English version of the string, and the value is the localized translation. For your French strings file, translate each “value”, but do not edit the “key”.
  4. Don’t forget to add the file to the project.

.nib, .xib, and .storyboard files can also be localized. However, there is only one such file in the JUMP SDK that is localizable: JRPublishActivityController.xib. To localize this file in your own project, use XCode’s “Use Base Internationalization” feature to select this file and the target language. The output of this operation is a copy of JRPublishActivityController.xib in a subfolder of ./JREngage/Resources/xibs/ named with the language code of the target language.

For a list of language codes, see http://xml.coverpages.org/iso639a.html or buy the ISO standard at http://www.iso.org/iso/catalogue_detail.htm?csnumber=4766.

Generating the Capture User Model

Warning: If you are integrating with social sign-in only (that is, Engage-only), or integrating via the Phonegap plugin, you do not generate the Capture user model. Instead, follow the iOS Engage-Only Integration Guide.

You will need the JSON (version 2.53 or above) Perl module.

To install the Perl JSON module:

  1. Make sure that Perl is installed on your system. If it is not, consider using MacPorts or Homebrew to install Perl.
  2. With Perl installed, install cpanm: sudo cpan App::cpanminus.
  3. Install the JSON Perl module by running: sudo cpanm --with-recommends JSON.

After you install the Perl JSON module, run the schema parsing Perl script to generate the Capture user model:

  1. Go to the Capture dashboard and sign in (https://janraincapture.com).
  2. Use the App drop-down menu to select your Capture app.
  3. Select the Schema tab.
  4. Use the Entity Types drop-down menu to select the correct schema. Wait for the page to reload. (If you are already on the correct schema, the page will not reload.)
  5. Click Download schema.

With the schema downloaded, generate the user model:

  1. Change into the script directory: $ cd jump.ios/Janrain/JRCapture/Script. Warning: CaptureSchemaParser.pl must be executed while from its directory.
  2. Run the CaptureSchemaParser.pl script, passing in your Capture schema as an argument with the -f flag, and the path to your Xcode project with the -o flag: $ ./CaptureSchemaParser.pl -f PATH_TO_YOUR_SCHEMA.JSON -o PATH_TO_YOUR_XCODE_PROJECT_DIRECTORY.

    The script writes its output to:

    PATH_TO_YOUR_XCODE_PROJECT_DIRECTORY/JRCapture/Generated/

Adding the Generated Capture User Model

Once generated, the user model must be added to your Xcode project:

  1. Choose File > Add Files to “Project Name”… and select the folder containing the generated user model.
  2. Click Add.
  3. Make sure that your project builds.

Working with ARC

As of v3.7.0, the JUMP iOS SDK uses ARC for object memory management.

Upgrading from an Earlier Version of the JUMP SDK

To update the library references in Xcode, remove the JREngage group and re-add it:

  1. Open your project in Xcode.
  2. In the Project Navigator pane, locate the JREngage folder (group) of your Xcode project.
  3. Right-click the JREngage project group and click Delete from the context menu.
  4. Do the same for the Janrain project group.
  5. In the dialog, make sure to select the Remove References button.
  6. Re-add the project groups, following the instructions in this guide.

Next

If you are integrating the JUMP platform (which includes Engage and Capture), see the JUMP for iOS Integration Guide.

If you are doing a social sign-in-only integration (that is, an Engage-only integration), see the iOS Engage-Only Integration Guide.

Android Studio Import Guide

This guide shows how to add the JUMP library to your Android Studio project.

Add the Library to Your Android IntelliJ Project

  1. Open Android Studio.
  2. In the main file menu, select Open.
  3. Select Import Module.
  4. Select the Jump folder from your local version of the Git repo.
  5. Set the module name to “:Jump”.
  6. Click Finish.

Android Authentication Token URL

Server-side Authentication

You will also want to configure a Social Login application.

To access any of the extra features available in the Janrain Engage API, or to complete server-side authentication, implement a token URL:

  1. Create a server-side HTTP or HTTPS endpoint (preferably HTTPS). This will be your auth_info token URL, and mobile devices running your mobile app will POST an Engage auth_info token to this endpoint, in exchange for an access token for your web service.
  2. From the new endpoint, extract the token. It’s POSTed in a parameter named token.
  3. Call auth_info. Supply the token just received, and your application’s 40-character Engage API key.
  4. Process the profile data returned from auth_info and log your user into your web application. (The unique and secure key you should use to identify the user is the identifier field of the profile node). As necessary, create and return access tokens or session cookies in your endpoint’s response. Your mobile app will receive that response.

For example, in Ruby on Rails, you might rely on the ActionController session and the cookie that it sets like this:

# The following helper class is from the Engage sample code found at
# https://github.com/janrain/Janrain-Sample-Code
ENGAGE = Rpx::RpxHelper.new("your_api_key_here",
                            "http://rpxnow.com",
                            "your_engage_app_realm_here") # e.g. mytestapp

# This is the Engage auth_info token URL -- the endpoint which spawns
# new mobile user sessions.
def mobileEngageSignIn
   auth_info = ENGAGE.auth_info(params[:token])

   identifier = auth_info['identifier']

   user = User.find_or_create_by_engage_identifier(identifier)
   # do other stuff, like populate the User record with the auth_info

   session[:user_id] = user.id
end

If you’re using the Rails ActionController session, set the cookie expiration to an appropriate value for a mobile device:

# This initializer block is found in app/config/environment.rb
Rails::Initializer.run do |config|
  config.action_controller.session[:session_expires] = 10.years.from_now
end

Then, make sure that you save the cookie in your mobile app. For example:

org.apache.http.cookie.Cookie[] mSessionCookies;

public void jrAuthenticationDidReachTokenUrl(String tokenUrl,
                                             HttpResponseHeaders responseHeaders,
                                             String tokenUrlPayload,
                                             String provider) {
    mSessionCookies = responseHeaders.getCookies();
}

From your new auth_info token URL, you can also access other Engage features. For example, you could call get_contacts and use the returned contact list to find other users of your mobile app that this user may know.

Note: Some features are limited to Pro, Plus, or Enterprise customers only.

To configure the library with your token URL, pass it to initInstance when initializing the library:

private static final String ENGAGE_APP_ID = "";
private static final String ENGAGE_TOKEN_URL = "";
private JREngage mEngage;
private JREngageDelegate mEngageDelegate;

...

mEngage = JREngage.initInstance(this, engageAppId, engageTokenUrl, mEngageDelegate);

Alternatively, you can change the token URL at any time using the setTokenUrl method:

JREngage mEngage;

...

mEngage.setTokenUrl(newTokenUrl);

You may configure the library with a null or empty token URL, and this authentication step will be skipped.

Whether or not the library posts the token to the token URL, your Android application must not contain your Engage API key.

Eclipse Import Guide

Deprecation Notice

As of version 6.0.0, Eclipse IDE support has been dropped. The Eclipse IDE was not tested with version 6.0.0 of the Janrain Android Mobile Libraries. All information in this document pertains to versions prior to 6.0.0 but may still be applicable if you are using the Eclipse IDE.

Overview

This guide covers the following areas:

Clone the Mobile Libraries and Sample Code Repository

Clone the Janrain JUMP for Android library from GitHub:

git clone git://github.com/janrain/jump.android.git

Add the Library to Your Android Eclipse Project

  1. Ensure that the Android ADT plug-in is installed.
  2. In Eclipse, select File > Import.
  3. Select Android > Existing Android Code Into Workspace and click Next.
  4. Click Browse, browse to .../jump.android/Jump, and click Open. Do not select Copy projects into workspace.
  5. Click Finish.
  6. In the Package Explorer, select your project.
  7. From the Project menu, select Properties.
  8. In the left list, select Android.
  9. In the Library section, click Add.
  10. Select Jump and click OK.
  11. Click Apply.
  12. If your project already includes a copy of the Android Support Library (android-support-v4.jar), browse to .../jump.android/Jump/libs/, delete android-support-v4.jar, and skip to step 17.
  13. Using the already-open Properties window for your project, select Java Build Path in the left list.
  14. Select the Libraries tab.
  15. Click Add JARs.
  16. In Jump/libs/, select android-support-v4.jar, okhttp-2.2.0.jar, okhttp-apache-2.2.0.jar, and okio-1.2.0.jar, and click OK.
  17. Open the Jump project’s Properties window.
  18. Set the Project Build Target of the Jump Eclipse project to API level 15 or above. (Eclipse may have reset the Jump project build target to a lower level.)
  19. Your project should now build and run.

Warning: Because the JUMP for Android library provides Android resources, it is not sufficient to add jump.jar to your Eclipse project build path–you must declare the Android library project dependency as detailed.

Warning: There can only be one version of android-support-v4.jar in the accumulated set of Java Build Path values for your workspace (although there may be more than one copy of the same version). If you have a conflict, delete one of the versions from the libs subdirectory of either the JUMP Mobile Libraries and Sample Code or from your project.

Phonegap Integration

  1. Go through steps 1-5 in Add the Library to Your Android Eclipse Project.
  2. Repeat steps 1-5 in Add the Library to Your Android Eclipse Project for the .../jump.android/JREngagePhonegapPlugin folder.
  3. In Add the Library to Your Android Eclipse Project, follow steps 9 and 10 but instead of adding an Android library dependency to Jump, add a library dependency to JREngagePhonegapPlugin.
  4. Open the project properties for the JREngagePhonegapPlugin project.
  5. Select Java Build Path in the left list.
  6. Select the Libraries tab.
  7. Click Add JARs.
  8. In your_project/libs/, select cordova-2.3.0.jar and click OK.
  9. Add the <activity> tags as documented in the JUMP for Android Guide.
  10. Add this to the <plugins> tag in your_project/res/config.xml: <plugin name="JREngagePlugin" value="com.janrain.android.engage.JREngagePhonegapPlugin"/>.

Troubleshooting Build and Runtime Errors

  • Error retrieving parent for item:

    jump.android/Jump/res/values-v11/styles.xml:3: error: Error retrieving parent for item: No
    resource found that matches the given name '@android:style/Theme.Holo.Light.DialogWhenLarge.NoActionBar'.
    

    Ensure that the project build SDK is Android API level 13 or higher. Note that this setting is different than the targeted API level. See the IDE setup instructions.

  • package android.support.v4.app does not exist

    jump.android/Jump/src/com/janrain/android/engage/ui/JRUiFragment.java
    package android.support.v4.app does not exist
    

    Ensure that the android-support-v4 library is defined in your IDE and that it references the jump.android/Jump/libs/android-support-v4.jar file.

  • package com.janrain.android.engage.net.async does not exist

    Try cleaning and rebuilding your project. If you are compiling with Eclipse, close and restart Eclipse.

Next

Follow the JUMP for Android Integration Guide.

Android Engage Custom Provider Guide

This guide describes the process of configuring custom OpenID and custom SAML providers in the Engage library. This guide assumes you have already completed either the Android Engage-only Integration Guide or the JUMP for Android Integration Guide.

Step Overview

  1. Gather configuration details.
  2. Configure and initialize the library.
  3. Begin authentication.

Gather Configuration Details

For each custom provider you want to configure, gather the following configuration details:

  • Provider ID - A short string which will be used to refer to the custom provider. For example, the provider ID for Yahoo! is “yahoo”. This is used only in the context of the Android app, and can be any arbitrary value you choose.
  • Friendly name - A string representing the user-facing name of the provider. For example, the friendly name for Yahoo! is “Yahoo!”.

Custom Open ID

In addition to the configuration details above you will need:

  • The OpenID identifier of your custom OpenID provider. For example, https://my-custom-openid-provider.com/example-openid-identifier.
  • Optionally, a custom opx_blob parameter for use with Janrain Identity Services’ OpenID providers.

Custom SAML

In addition to the configuration details above you will need:

  • The name of the SAML implementation in Engage for your custom SAML provider.

Configure and Initialize the Library

Engage-only Integration

Construct a Map<String, JRDictionary similar to this example. The field names in the JRDictionary are important (that is, the field for friendly name must be friendly_name). The keys in the map are the Provider IDs.

Map<String, JRDictionary> customProviders = new HashMap<String, JRDictionary>();

JRDictionary openIdProvider = new JRDictionary();
openIdProvider.put("friendly_name", "Example Custom OpenID Provider");
openIdProvider.put("openid_identifier", "https://my-custom-openid-provider.com/example-openid-identifier");
openIdProvider.put("opx_blob", "some_blob_for_opx"); // This is an optional field
openIdProvider.put("icon_resource_id", R.drawable.openIdIcon);  // This is an optional field

customProviders.put("open_id_provider", openIdProvider);

JRDictionary samlProvider = new JRDictionary();
samlProvider.put("friendly_name", "Example Custom SAML Provider");
samlProvider.put("saml_provider", "the_name_of_the_engage_implementation_of_the_saml_provider");
samlProvider.put("icon_resource_id", R.drawable.samlIcon); // This is an optional field

customProviders.put("saml_provider", samlProvider);

Then pass the map in as an argument to JREngage.initInstance:

engage = JREngage.initInstance(context, "your-engage-app-id", "your-token-url", delegate,
                               customProviders);

Jump Integration

JumpConfig provides convenience methods for adding custom providers:

JumpConfig jumpConfig = new JumpConfig();
... // Your Jump configuration

jumpConfig.addCustomOpenIdProvider("open_id_provider", "Example Custom OpenID Provider",
                                   "https://my-custom-openid-provider.com/example-openid-identifier",
                                   "some_blob_for_opx", R.drawable.openIdIcon);

jumpConfig.addCustomSamlProvider("saml_provider", "Example Custom SAML Provider",
                                 "the_name_of_the_engage_implementation_of_the_saml_provider",
                                 R.drawable.samlIcon);

Now initialize Jump as normal:

Jump.init(this, jumpConfig);

Icons

You can add a 30x30 provider icon for your custom providers by passing in the icon’s resource ID as an argument to addCustomSamlProvider or addCustomOpenIdProvider for JUMP integrations, or in the JRDictionary with the key open_id_provider for Engage-only integrations.

Begin Authentication

Begin authentication as in the Integration Guides.

Android Engage-only Integration Guide

This guide describes how to integrate Engage-only into your Android app. For a description of integration steps for the JUMP platform, see the JUMP for Android Integration Guide.

Step Overview

  1. Gather configuration details.
  2. Add the necessary library dependency to your project.
  3. Declare the library project dependency.
  4. Add library-required activities permissions to your AndroidManifest.xml file.
  5. Import and initialize the library.
  6. Begin authentication by calling one of the two show...Dialog methods.
  7. Receive your authentication token URL’s response in JREngageDelegate#jrAuthenticationDidReachTokenUrl().

Gather Configuration Details

Configure your desired set of social identity providers in the Engage dashboard. See Identity Providers for more information.

Configure the Providers Used in the Android Library

Once the providers are configured, they need to be enabled explicitly for the native Android Engage Library.

While signed in to the Engage dashboard, display the Engage for Android Configuration Wizard (in the drop-down menus, select Deployment > Engage for Android). Follow the wizard to configure the providers used for authentication and social sharing from the Android library.

Retrieve your Engage Application ID

You will also need your 20-character application ID from the Engage dashboard. Click the Home link in the Engage dashboard. Your app ID is displayed in the right-most column towards the bottom of the column under the Application Info header.

Declare the Library Dependency

If you are using Eclipse, see the Eclipse Import Guide. If you are using IntelliJ or Android Studio it’s way easier (import the JUMP module and add a module dependency to it).

If you are using the Ant build tool chain, use android update project -p path/to/your/prj -l path/to/jump.android/Jump.

Declare the JUMP Activities

Ensure the declaration of the android.permission.INTERNET permission in your <uses-permission> element and copy from .../Jump/AndroidManifest.xml, adding the following two <activity> XML elements to your project’s AndroidManifest.xml file:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="13" />

  ...

  <application ... >

  ...

    <!-- The following activities are for the Janrain Engage for Android library -->
    <!-- This activity must have a dialog theme such as Theme.Holo.Dialog, or
        Theme.Dialog, etc.

        Using android:theme="@style/Theme.Janrain.Dialog" will result in Theme.Dialog on API 4-10 and
        Theme.Holo.DialogWhenLarge.NoActionBar on API 11+
    -->
    <activity
        android:name="com.janrain.android.engage.ui.JRFragmentHostActivity"
        android:configChanges="orientation|screenSize"
        android:theme="@style/Theme.Janrain.Dialog.Light"
        android:windowSoftInputMode="adjustResize|stateHidden"
        />

    <!-- This activity must have a normal (non-dialog) theme such as Theme, Theme.Light, Theme.Holo, etc.

        Using android:theme="@style/Theme.Janrain" or "@style/Theme.Janrain.Light" will result in
        Theme (or Theme.Light) on API 4-10 and
        Theme.Holo (or Theme.Holo.Light) on API 11+
    -->
    <activity
        android:name="com.janrain.android.engage.ui.JRFragmentHostActivity$Fullscreen"
        android:configChanges="orientation|screenSize"
        android:theme="@style/Theme.Janrain.Light"
        android:windowSoftInputMode="adjustResize|stateHidden"
        />

  ...

  </application>

</manifest>

Note: You can target a version of Android lower than 13 (which is 3.2). To do so, change the android:targetSdkVersion to your desired deployment target. You must still build against API 13+ even when targeting a lower API level. The build SDK used when compiling your project is defined by your project’s local.properties:

  • android list target to get a list of targets available in your installation of the Android SDK.
  • android update project -p path/to/project -t target_name_or_target_installation_id to update the build target SDK for your project (note that this does not affect your project’s minSdkVersion or targetSdkVersion).

Import and Initialize

Import the following classes:

import com.janrain.android.engage.JREngage;
import com.janrain.android.engage.JREngageDelegate;
import com.janrain.android.engage.JREngageError;
import com.janrain.android.engage.net.async.HttpResponseHeaders;
import com.janrain.android.engage.types.JRActivityObject;
import com.janrain.android.engage.types.JRDictionary;

Interaction begins by calling the JREngage.initInstance method, which returns the JREngage object:

private static final String ENGAGE_APP_ID = "";
private static final String ENGAGE_TOKEN_URL = "";
private JREngage mEngage;
private JREngageDelegate mEngageDelegate = ...;

...

mEngage = JREngage.initInstance(this.getApplicationContext(), ENGAGE_APP_ID, ENGAGE_TOKEN_URL, this);

initInstance takes four arguments:

  • context — Your Android application context.
  • appId — Your Engage application ID (found on the Engage dashboard).
  • tokenUrl — Your web server’s authentication token URL.
  • delegate — An implementation of the JREngageDelegate interface through which you will receive callbacks from the library.

Choosing your Engage Delegate Class

Select a class you will use to receive callbacks from the Engage library (this is called your Engage delegate). The delegate should be a singleton object. A good place to start is your app’s Android Application class (if you have one). Activities that are always at the root of the back stack can be acceptable choices. Avoid using Activities which will be short-lived.

Social Sign-in

An Engage authentication is meaningful in the context of authenticating your mobile app to something. If you are unsure what your users should be authenticating to, Janrain Capture may be a great choice. (Capture signs authenticating users into your copy of their social profile, giving your mobile app a place to store and retrieve data from, and a pier from which to build out a service.)

Once the JREngage object has been initialized, start authentication by calling the showAuthenticationDialog method:

mEngage.showAuthenticationDialog();

You will receive your authentication token URL’s response in the jrAuthenticationDidReachTokenUrl method. When received, you will have access to the body of the response, as well as the headers, which frequently contain session cookies used to coordinate the app’s session with your web server. Parsing your authentication token URL’s response for session-establishing information, or retrieving session cookies from the header, is your app’s responsibility.

For guidance implementing your web server’s authentication token URL, see Android Authentication Token URL.

Social Sharing

If you want to share an activity, first create an instance of the JRActivityObject:

String activityText = "added JREngage to her Android application!";
String activityLink = "http://janrain.com";

JRActivityObject jrActivity = new JRActivityObject(activityText, activityLink);

Populate the new object with information about the activity being shared. Here, an exciting Facebook “action link” is added:

activityObject.addActionLink(new JRActionLink("Download the Quick Share demo!",
      "https://market.android.com/details?id=com.janrain.android.quickshare");

Then pass the activity to the showSocialPublishingDialogWithActivity method:

mEngage.showSocialPublishingDialogWithActivity(jrActivity);

JUMP for Android Integration Guide

This guide describes integrating the Janrain User Management Platform into your Android app. This includes the Capture user registration system. For Engage-only (that is, social authentication-only) integrations, see the Android Engage-only Integration Guide.

Warning: You must have a flow configured with your Capture instance in order to use the Capture library.

Upgrading to v6.0

  • Important: This is the last release of this form of the Janrain Android Mobile Libraries. Other than major bug fixes or compatibility updates, no further implementations will be released. A new Android Sample Application will be written using more modern Android tools and libraries (release date is unscheduled at this time).
  • Android Studio IDE is the only IDE that this release supports and has been tested with.
  • The Android Mobile libraries have removed all inter-dependencies on the Google, Facebook, and Twitter SDKs and libraries. The SimpleDemoNative app has been created to demonstrate how to integrate native provider logon for these providers using their SDKs and libraries. Refer to the Android Native Authentication Guide for more information.
  • Note: Google Play/Sign-On libraries newer than version 8.1 are NOT supported. Google has changed the oAuth access token provisioning as of version 8.3 and it is no longer compatible with Janrain’s APIs at the time of this release. We will be updating our APIs to support Google’s re-architecture in the future.
  • If your previous project had implemented native provider authentication, you must re-implement this as outlined in the Android Native Authentication Guide and the SimpleDemoNative sample application.
  • If you want to use the Janrain Mobile libraries and sample code with the latest Android API levels, there are now dependencies on the deprecated org.apache.http.legacy.jar. This file is included in the Github repo in the libs folder. Additional information on this can be found in the build.gradle file.

Features

  • Engage Social Sign-in (includes OpenID and many OAuth identity providers such as Google, Facebook, and so on).
  • Sign-in to Capture accounts:
    • Either via Engage Social Sign-in or via traditional username/password sign-in.
    • Including the Capture “merge account flow” (which links two social accounts by verified email address at sign-in time).
  • Capture account record updates.
  • Capture account “thin” social registration (automatic account creation for Social Sign-in users).

In the Pipeline

  • Profile updates (including password and email address updates).
  • In-app forgot password flow initiation.
  • Social account linking (like the “merge account” sign-in flow, but after a user is signed in).
  • Session refreshing (sessions currently last one hour).

Step Overview

Basic use flow:

  1. Gather your configuration details.
  2. Declare the library project dependency and add the required elements to your AndroidManifest.xml file.
  3. Initialize the library.
  4. Start a sign-in.
  5. Read and modify the record.
  6. Send record updates.
  7. Persist the local user object.

Gather your Configuration Details

Before you begin integrating, you will need an array of configuration details:

  1. Sign in to your Engage Dashboard (https://rpxnow.com)
    1. Configure the social providers you wish to use for authentication (select Deployment > Engage for Android).
    2. Retrieve your 20-character Engage application ID from the Engage dashboard (in the right column of the Home page, on the Engage dashboard).
  2. Ask your deployment engineer or account manager for your Capture domain.
  3. Create a new Capture API client for your mobile app by signing in to the Capture dashboard and provisioning a new API client for your mobile app.

    Warning: login_client is mutually exclusive with all other API client features, which means only login clients can be used to sign in users, and only non-login clients can perform client_id and client_secret authenticated Capture API calls. This means that you cannot use the owner client as a login client.

    Warning: If you do not set the write_with_token access schema for your API client to include the attributes your client will write to in its write access schema, you will receive missing attribute errors when attempting to update attributes.

  4. Discover your flow settings. Ask your deployment engineer for:

    • The name of the Capture flow you should use.
    • The name of the flow’s traditional sign-in form.
    • The name of the locale in the flow your app will use (the value for US English is en-US).
    • The appropriate values for the settings default_flow_name and default_flow_version. Set these settings for your new API client in the Settings section of the Janrain Capture dashboard (https://janraincapture.com).
  5. Determine whether your app should use “thin” or “two-step” social registration.

  6. Determine the name of the traditional sign-in key attribute (for example, email or username).

Warning: You must create a new API client with the correct login_client feature in order to use the JUMP native mobile libraries.

Declare and Import

Declare the Android Library Project Dependency

Using the Android command line tool, execute the following command from the directory of your project’s AndroidManifest.xml file:

android update project -p . -l ../path/to/jump.android/Jump

Declare the JUMP Activities

  1. Make sure you have the android.permission.INTERNET permission in your <uses-permission> element.
  2. From .../Jump/AndroidManifest.xml, copy the following two <activity> XML elements and add them to your project’s AndroidManifest.xml file:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
    
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="13" />
    
      ...
    
      <application ... >
    
      ...
    
        <!-- The following activities are for the Janrain Engage for Android library -->
        <!-- This activity must have a dialog theme such as Theme.Holo.Dialog, or
            Theme.Dialog, etc.
    
            Using android:theme="@style/Theme.Janrain.Dialog" will result in Theme.Dialog on API 4-10 and
            Theme.Holo.DialogWhenLarge.NoActionBar on API 11+
        -->
        <activity
            android:name="com.janrain.android.engage.ui.JRFragmentHostActivity"
            android:configChanges="orientation|screenSize"
            android:theme="@style/Theme.Janrain.Dialog.Light"
            android:windowSoftInputMode="adjustResize|stateHidden"
            />
    
        <!-- This activity must have a normal (non-dialog) theme such as Theme, Theme.Light, Theme.Holo, etc.
    
            Using android:theme="@style/Theme.Janrain" or "@style/Theme.Janrain.Light" will result in
            Theme (or Theme.Light) on API 4-10 and
            Theme.Holo (or Theme.Holo.Light) on API 11+
        -->
        <activity
            android:name="com.janrain.android.engage.ui.JRFragmentHostActivity$Fullscreen"
            android:configChanges="orientation|screenSize"
            android:theme="@style/Theme.Janrain.Light"
            android:windowSoftInputMode="adjustResize|stateHidden"
            />
    
      ...
    
      </application>
    
    </manifest>
    

Note: You can target a version of Android lower than 17, but Janrain does not support this. To do so, change the android:targetSdkVersion to your desired deployment target. You must still build against API 17+, even when targeting a lower API level. The build SDK used when compiling your project is defined by your project’s local.properties android list target to get a list of targets available in your installation of the Android SDK. Use android update project -p . -t target_name_or_target_installation_id to update the build SDK for your project. (Note that this does not affect your project’s minSdkVersion or targetSdkVersion.)

Import the Library

Import the following classes:

import com.janrain.android.Jump;
import com.janrain.android.capture.Capture;
import com.janrain.android.capture.CaptureApiError;

Initialize the Library

Initialize the library by calling the Jump#init method. For example:

String engageAppId = "your Engage App ID";
String captureDomain = "your Capture domain";
String captureClientId = "your Capture Client ID";
String captureLocale = "your Capture flow locale";
String captureSignInFormName = "your Capture sign-in form's name";
String forgottenPasswordFormName = "your Capture forgot password form name";
Jump.TraditionalSignInType signInType = Jump.TraditionalSignInType.EMAIL; // or USERNAME
Jump.init(this, engageAppId, captureDomain, captureClientId, captureLocale, captureSignInFormName,
        signInType);

Start a Sign-in

Once the JUMP library is initialized, your application can start the sign-in flow by calling the sign-in dialog display method com.janrain.android.Jump#showSignInDialog. You need to define a callback handler which implements the com.janrain.android.Jump.SignInResultHandler interface. For example:

private class MySignInResultHandler implements Jump.SignInResultHandler, Jump.SignInCodeHandler {
    public void onSuccess() {
        AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
        b.setMessage("Sign-in complete.");
        b.setNeutralButton("Dismiss", null);
        b.show();
    }

    // Part of the com.janrain.android.Jump.SignInCodeHandler interface
    public void onCode(String code) {
        // Do something with the Access Code
    }

    public void onFailure(SignInError error) {
        AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
        b.setMessage("error:" + error);
        b.setNeutralButton("Dismiss", null);
        b.show();
    }
}

Now call com.janrain.android.Jump#showSignInDialog with an instance of your callback handler class:

Jump.showSignInDialog(MainActivity.this, null, new MySignInResultHandler());

Implementing the com.janrain.android.Jump.SignInCodeHandler interface is optional. When the sign-in has succeeded, onCode(String code) is called with a Capture OAuth authorization code that can be used by a server-side application (for example, the Capture Drupal Plugin) to retrieve an access token.

Traditional Sign-in and Social Sign-in

The Capture libraries support both social sign-in via Engage (for example, Facebook) as well as traditional sign-in (that is, username and password or email and password sign-in). There are three main ways to start sign-in:

  • Jump.showSignInDialog(Activity, String, SignInResultHandler, String)–Starts the Engage social sign-in process. If the provider argument (the second parameter) is null, sign-in begins by displaying a list of all currently-configured social sign-in providers, and guiding the user through the authentication.
  • Jump.showSignInDialog(Activity, String, SignInResultHandler, String)–If called with a non-null string for the second argument, it proceeds directly to the provider. For example, “facebook” starts a sign-in directly with Facebook.
  • Jump.performTraditionalSignIn(String, String, SignInResultHandler, String)–Starts the traditional sign-in flow headlessly (with no user experience).

The fourth string parameter is the merge token paremeter. It is used in the second step of the “Merge Account Flow”, described below.

Handling the Merge Account Sign-in Flow

Sometimes a user creates a record with one means of sign-in (for example, a traditional username and password record) and later attempts to sign in through a different means (for example, with Facebook).

When this happens, the sign-in cannot succeed because there is no Capture record associated with the social sign-in identity and the email address from the identity is already in use.

Before being able to sign in with the social identity, the user must merge the identity into the user’s existing record. This is called the Merge Account Flow.

The merge is achieved at the conclusion of a second sign-in flow authenticated by the record’s existing associated identity. The second sign-in is initiated upon the failure of the first sign-in flow, and also includes a merge token that Capture uses to merge the identity from the first (failed) sign-in into the record.

Capture Libraries Event Sequence for Merge Account Flow

  1. User attempts to sign in with a social identity (“identity F”).
  2. Capture sign-in fails because there is an existing Capture record connected to “identity G” that shares some constrained attributes with “identity F”. For example, the two identities have the same email address.
  3. The SignInResultHandler has its failure callback invoked with an error representing this state. You can recognize this case via the isMergeFlowError() method of the contained captureApiError, like this:

    error.reason == SignInError.FailureReason.CAPTURE_API_ERROR &&
    error.captureApiError.isMergeFlowError())
    
  4. The host application (your mobile app) notifies the user of the conflict and advises the user to merge the accounts.

  5. The user elects to take action.

  6. The merge sign-in is started by invoking com.janrain.android.Jump#showSignInDialog with a merge token or by invoking com.janrain.android.capture.Capture.performTraditionalSignIn with a merge token. The existing identity provider of the record is retrieved with error.captureApiError.getExistingAccountIdentityProvider(), and the merge token with error.captureApiError.getMergeToken().

Example
public void onFailure(SignInError error) {
    if (error.reason == SignInError.FailureReason.CAPTURE_API_ERROR &&
            error.captureApiError.isMergeFlowError()) {
        final String mergeToken = error.captureApiError.getMergeToken();
        final String existingProvider = error.captureApiError.getExistingAccountIdentityProvider();
        String conflictingIdentityProvider = error.captureApiError.getConflictingIdentityProvider();
        String conflictingIdpNameLocalized = JRProvider.getLocalizedName(conflictingIdentityProvider);
        String existingIdpNameLocalized = JRProvider.getLocalizedName(conflictingIdentityProvider);

        AlertDialog alertDialog = new AlertDialog.Builder(fromActivity)
                .setTitle("Email Address Conflict")
                .setCancelable(false)
                .setMessage("The " + conflictingIdpNameLocalized + " account that you signed in with has"
                        + " the same email address as an existing user. Sign in with " +
                        existingIdpNameLocalized + " to continue.")
                .setPositiveButton(fromActivity.getString("Merge"),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                // When existingProvider == "capture" you can also call ...
                                //
                                //     Jump.performTraditionalSignIn(String signInName, String password,
                                //         final SignInResultHandler handler, final String mergeToken);
                                //
                                // ... instead of showSignInDialog if you wish to create the dialog
                                // and then use the headless API to perform the traditional sign-in.
                                Jump.showSignInDialog(fromActivity,
                                        existingProvider,
                                        signInResultHandler,
                                        mergeToken);
                            }
                        })
                .setNegativeButton(android.R.string.cancel, null)
                .create();
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.show();
    }
}

This example:

  • Checks for the merge flow error.
  • Prompts the user to merge.
  • Starts authentication.

Note: The “existing provider” of the merge flow can be “capture” which represents Capture itself. This case occurs when the merge failure was a conflict with an existing record created with traditional sign-in. This case can be handled separately if you want to create the traditional sign-in UI, or you can call:

Jump.showSignInDialog(yourActivity, "capture", yourSignInResultHandler, yourMergeTokenFromTheError)

Baseline Merge User Interface

In order to lower the JUMP Mobile libraries and sample code integration overhead, the Mobile libraries and sample code provide a baseline user experience for the merge account flow. You can use the baseline UX to start exploring the feature. Later on, you can achieve more control over the UX by implementing your own UX and using the provided headless APIs to interact with Capture.

To invoke the baseline UX, call:

Jump.startDefaultMergeFlowUi(yourActivity, theOriginalSignInError, yourSignInResultHandler)

Read and Modify the Account Record

Capture Schema Basics

Capture user records are defined by the Capture schema, which defines the attributes of the record. An attribute is either a primitive value (a number, a string, a date, and so on), an object, or a plural.

Primitive attribute values are the actual data that make up your user record. For example, they are your user’s identifier, or email address, or birthday.

Objects and plurals make up the structure of your user record. For example, in the default Capture schema, the user’s name is represented by an object with six primitive values (strings) used to contain the different parts of the name. The six values are:

  • familyName
  • formatted
  • givenName
  • honorificPrefix
  • honorificSuffix
  • middleName

Objects can contain primitive values, sub-objects, or plurals, and those attributes are defined in the schema.

Plurals contain collections of objects. Each element in a plural is an object or another plural. Every element in a plural has the same set of attributes that are defined in the schema. Think of a plural as an object that may have zero or more instances.

Updating the User Profile

Update the properties of your CaptureRecord that correspond to the fields of the editProfileForm in your flow. For example: givenName, familyName, birthdate, aboutMe, and so on.

Call Capture.updateUserProfile with the CaptureRecord and a CaptureApiRequestCallback to update the user’s profile.

Upon a successful update the callback’s onSuccess method is called. If the update fails for any reason, the callback’s onFailure method is called with an error.

The following code sample shows how the SimpleDemo application updates a user’s profile:

try {
    user.put("email", email);
    user.put("displayName", displayName);
    user.put("givenName", firstName);
    user.put("familyName", lastName);
    user.put("aboutMe", about);
} catch (JSONException e) {
    throw new RuntimeException("Unexpected ", e);
}

Capture.updateUserProfile(user, new Capture.CaptureApiRequestCallback() {

    public void onSuccess() {
        Toast.makeText(UpdateProfileActivity.this, "Profile Updated", Toast.LENGTH_LONG).show();
        finish();
    }

    public void onFailure(CaptureApiError error) {
        AlertDialog.Builder adb = new AlertDialog.Builder(UpdateProfileActivity.this);
        adb.setTitle("Error");
        adb.setMessage(error.toString());
        adb.show();
    }
});

Read and Modify the Capture Record Model

You can retrieve the signed-in Capture user’s account record via Jump.getSignedInUser(). The record is an instance of org.json.JSONObject with some additional methods defined by the CaptureRecord subclass. You can read and write to the record via the usual JSONObject methods.

For example, to read the aboutMe attribute in the record:

Jump.getSignedInUser().optString("aboutMe")

You can also make changes. For example, to write to the aboutMe attribute in the record:

try {
    Jump.getSignedInUser().put("aboutMe", "Bacon, the healthiest of all vegetables.");
} catch (JSONException e) {
    throw new RuntimeException("Unexpected", e);
}

Any changes made to the record must still obey the entity type schema from Capture. For example, you cannot add dynamic new attributes, but you can add additional elements to plurals in the schema.

Send Record Updates to Capture

To push local changes to the Capture server, call com.janrain.android.capture.CaptureRecord#synchronize.

Call the Load and Store Hooks

Because Android can garbage-collect processes at its discretion, every app must persist its state when it may leave the foreground, and restore the persisted state when it restarts.

When your Android application starts, you must call com.janrain.android.Jump#loadFromDisk.

For example, from the SimpleDemo application object:

public class SimpleDemoApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        Jump.loadFromDisk(this);
    }
}

Whenever your Android application pauses, you must call com.janrain.android.Jump.saveToDisk.

For example, from MainActivity in SimpleDemo:

@Override
protected void onPause() {
    Jump.saveToDisk(this);
    super.onPause();
}

Sign the User Out

Call com.janrain.android.Jump.signOutCaptureUser to sign the user out.

Next: Registration

Once you have sign-in and record updates working, see the JUMP for Android User Registration Guide for information on new user registration.

Appearance Customization

Creating Your Own User Interface

You can create your own traditional sign-in user interface and use com.janrain.android.Jump.performTraditionalSignIn to sign in users. com.janrain.android.Jump.showSignInDialog also takes a provider name parameter which (if supplied) directs the library to begin the sign-in flow directly with that provider, skipping the stock list of sign-in providers user interface.

Customizing the Stock User Interface

The JUMP for Android Mobile libraries and sample code have an API for appearance customization, and allow for customization through the Android Theme system as well.

Troubleshooting

Attribute Does Not Exist

<CaptureApiError code: 223 error: unknown_attribute description: attribute does not exist: /your_attr_name>

Use entityType.setAccessSchema to add write access to this attribute to your native API client.

Android Native Authentication Guide

This guide describes how to integrate with native Android authentication systems. The Social Sign-in library has historically supported authentication by means of a WebView running a traditional web OAuth flow. Janrain now supports authentication by means of native identity provider libraries.

Supported Providers

  • Facebook
  • Google+ (Play/Sign-in SDK version 8.1 or lower ONLY–The Janrain APIs are not currently compatible with version 8.3 or newer.)
  • Twitter

Native Authentication for Janrain Mobile Libraries (Android version 6.0.0 or Newer)

There are potentially breaking changes to the Janrain Mobile libraries for Android with version 6.0.0. All dependencies on third-party SDKs and libraries around native social provider support (Google+ and Facebook) have been removed.

The Janrain Mobile libraries for Android no longer integrate third-party social provider SDKs or libraries. The SimpleCaptureNative app was created to demonstrate how to retrieve a native provider’s oAuth access token using the current (at the time of this release) native provider’s tools in as close a format to the native provider’s sample code on their website. You will now retrieve the native provider’s oAuth access token using their preferred method and initiate the Janrain authentication process using:

Jump.startTokenAuthForNativeProvider(final Activity fromActivity, final String providerName, final String accessToken, final String tokenSecret, SignInResultHandler handler, final String mergeToken)

Step Overview

  1. Configure the native authentication framework for the providers you want to support (Google+, Facebook, or Twitter).
  2. Give the user the option to sign in with a native provider or through a UIWebview dialog (for non-native providers).
  3. If the user selects to log in with a native provider, initiate the native provider’s SDK and retrieve a properly-scoped oAuth access token (and token secret for Twitter).
  4. Pass the native provider’s oAuth access token to the Janrain Mobile libraries where it will be posted to the Social Login server for verification. A Social Login access token will be returned.

Facebook

As of release 6.0.0, the following Facebook SDK version 4.9.0 implementation steps were implemented in the SimpleCaptureDemo sample application in order to retrieve the Facebook oAuth access token from the Android device:

  1. Download the Facebook SDK for Android from https://developers.facebook.com/docs/android or implement it through your Gradle build settings.
  2. Follow ALL of the steps on this page EXCEPT for step 2 (Create a Facebook App): https://developers.facebook.com/docs/android/getting-started/. In order for the Janrain Social Login server to validate the provided Facebook oAuth token, the token must be provisioned from the same Facebook application that is configured for the Janrain Social Login application. In most cases, you simply add an Android App Settings configuration to the existing Facebook app.
  3. Use this page as a starting point for implementing native Facebook login: https://developers.facebook.com/docs/facebook-login/android.
  4. Make sure that the permissions requested in the LoginManager.getInstance().logInWithReadPermissions(MainActivity.this, Arrays.asList("public_profile", "email")); method include the required permissions. In most cases, these permissions need to mirror the Facebook app permissions configuration of the Engage Social Login application that is configured in the Janrain Social Login dashboard.
  5. Refer to the MainActivity.java file for an example of how this was done with the SimpleDemoNative application using the Facebook SDK version 4.9.0.
  6. Once you have retrieved the oAuth access token from the Facebook SDK, you can initiate the Janrain authentication process with: Jump.startTokenAuthForNativeProvider(final Activity fromActivity, final String providerName, final String accessToken, final String tokenSecret, SignInResultHandler handler, final String mergeToken)

Google+

As of release 6.0.0, the following Google SDK version 8.1 (Play/Sign-in SDK version 8.1 or lower ONLY. The Janrain APIs are not currently compatible with version 8.3 or newer.) implementation steps were implemented in the SimpleDemoNative sample application in order to retrieve the Google+ oAuth access token from the Android device:

  1. Implement the following Gradle dependencies (see the build.gradle file in the SimpleDemoNative sample app for a full implementation):

    classpath 'com.google.gms:google-services:1.3.0'
    and
    compile 'com.google.android.gms:play-services:8.1.0'
    compile 'com.google.android.gms:play-services-plus:8.1.0'
    compile 'com.google.android.gms:play-services-identity:8.1.0'
    
  2. Follow all of the steps on this page that involve the project configuration and Google+ app configuration: https://developers.google.com/identity/sign-in/android/start. In order for the Janrain Social Login server to validate the provided Google+ oAuth token, the token must be provisioned from the same Google+ application that is configured for the Janrain Social Login application. In most cases, you simply add an Android app client ID configuration to the existing Google+ app.

  3. In the case of the SimpleDemoNative application, the integration steps were implemented in the MainActivity.java file with minimal changes from the examples provided by Google at this link: https://developers.google.com/identity/sign-in/android/sign-in.

  4. Make sure that the scopes requested when configuring the Google API client include the required scopes. In most cases these scopes need to mirror the Google+ app permissions configuration of the Engage Social Login application that is configured in the Janrain Social Login dashboard. For example:

    mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this).addOnConnectionFailedListener(this).addApi(Plus.API).addScope(new Scope(Scopes.PROFILE)).addScope(new Scope(Scopes.EMAIL)).build();
    
  5. Refer to the MainActivity.m file for an example of how this was done with the SimpleDemoNative application.

  6. Once you have retrieved the oAuth access token from the Google+ SDK, you can initiate the Janrain authentication process with:

    Jump.startTokenAuthForNativeProvider(final Activity fromActivity, final String providerName, final String accessToken, final String tokenSecret, SignInResultHandler handler, final String mergeToken)
    

Twitter

As of release 6.0.0, the following Twitter Fabric, TwitterKit SDK implementation steps were implemented in the SimpleDemoNative sample application in order to retrieve the Twitter oAuth access token from the Android device:

  1. Download the Fabric SDK (https://get.fabric.io/) and include TwitterKit.
  2. Configure your Twitter App: http://docs.fabric.io/android/twitter/configure-twitter-app.html. In order for the Janrain Social Login server to validate the provided Twitter oAuth token, the token must be provisioned from the same Twitter application that is configured for the Janrain Social Login application. In most cases, you simply add an Android app client ID configuration to the existing Twitter app.
  3. In the case of the SimpleDemoNative application, the integration steps were implemented in the MainActivity.java file with minimal changes from the examples provided by Twitter at this link: http://docs.fabric.io/android/twitter/authentication.html.
  4. Note: In most default cases, Twitter will not return an email address for an end user. This may cause account merging or linking issues if your Registration user experience relies heavily on merged social profiles. This use case is typically addressed by forcing Twitter account holders to use the “Account Linking” functionality of the SDK. Customers may choose to work with Twitter to get their application white-listed so it will attempt to return an email address from a user profile. However, email addresses are not “required” for Twitter accounts; subsequently, there is still no guarantee that an email address will be returned.
  5. Refer to the MainActivity.java file for an example of how this was done with the SimpleDemoNative application.
  6. Once you have retrieved the oAuth access token AND token secret from the TwitterKit SDK, you can initiate the Janrain authentication process with: Jump.startTokenAuthForNativeProvider(final Activity fromActivity, final String providerName, final String accessToken, final String tokenSecret, SignInResultHandler handler, final String mergeToken)

DEPRECATED: Native Authentication Implementation for Janrain Mobile Libraries (Android versions prior to version 6.0.0)

Previous versions of the Janrain Mobile libraries for Android (before version 6.0) attempted to use reflection to call the native provider SDKs and retrieve the oAuth access token. This presented a maintenance and compatibility issue, with the Janrain Mobile libraries for Android able to only support specific versions of the native provider SDKs. The following documentation will be removed in a subsequent release but is preserved for customers using older versions of the Janrain Mobile libraries for Android.

Native authentication is supported by the Social Sign-in library, and is compatible with both the sign-in-only and user registration deployments.

Supported Providers

  • Facebook
  • Google+

At this time, native authentication is available for authentication only, and not for social identity resource authorization (for example, sharing).

The Mobile libraries and sample code are not currently able to request the same scopes that are configured in the Engage dashboard when using native authentication. This will be available in a future release. For now, Facebook requests basic_info and Google+ requests plus.login.

Step Overview

  1. Configure the native authentication framework.
  2. Start authentication.
  3. The library will delegate the authentication to the native authentication framework.
  4. The library delegate message will fire when native authentication completes.

Facebook

Configure the Native Authentication Framework

Follow the steps for creating a new Android project in the Getting Started with the Facebook SDK for Android guide at https://developers.facebook.com/. Stop before the section A minimum viable social application.

Make sure that both your Android application and Social Sign-in app are configured to use the same Facebook application app ID.

Begin Sign-in or Authentication

Start authentication or sign-in as normal. If the Facebook Android Mobile libraries and sample code are compiled into your app, they will be used to perform all Facebook authentication.

Signing Out

Following Facebook’s documentation, we’ll use closeAndClearTokenInformation to close the in-memory Facebook session.

  1. Import the Facebook Session class:

    import com.facebook.Session;
    
  2. Call closeAndClearTokenInformation when your sign-out button is pressed. For example, in SimpleDemo, we add the following code to the onClickListener for the signOut button:

    signOut.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            ...
            // Sign out of the Facebook SDK
            Session session = Session.getActiveSession();
            if (session == null) {
                session = new Session(MainActivity.this);
                Session.setActiveSession(session);
            }
            session.closeAndClearTokenInformation();
        }
    });
    

Note: This does not revoke the application’s access to Facebook. So if a user has a Facebook account set up in the Facebook app, it will continue to be used to sign in without asking to be reauthorized.

Note: The context that is passed into the Session constructor should match the context that you passed into JUMP when showing the sign-in dialog.

Release Builds

If you plan to use ProGuard on your release builds, add the following code to your ProGuard configuration file:

-keep class com.facebook.** {*;}
-keepattributes Signature

Google+

Configure the Native Authentication Framework

Follow the Google+ Platform Getting Started directions up to Initalize the Plus Client. For native Google+ authentication to work via Social Sign-in, both Janrain and the Google+ Android SDK must be configured to use the same Google+ project in the Google Cloud Console.

Configure JUMP

By default, the JUMP library will silently fail when Google Play Services is unavailable, then attempt to sign in using a WebView. If you want the SDK to present Google’s dialog suggesting that the user install or update or configure Google Play Services when the error is either SERVICE_MISSING, SERVICE_VERSION_UPDATE_REQUIRED, or SERVICE_DISABLED, then set:

jumpConfig.tryWebViewAuthenticationWhenGooglePlayIsUnavailable = false;

Or, for an Engage-only integration:

engage.setTryWebViewAuthenticationWhenGooglePlayIsUnavailable(false);

After the dialog is dismissed, the library will call your onFailure method. If the error is something else, the SDK will fail silently and attempt sign-in using a WebView.

Signing out of the Google+ SDK

You should provide your users with the ability to sign out of the Google+ SDK. This will allow them to sign in again with a different account if they have multiple Google+ accounts on their Android devices. To do this, call:

Jump.signOutNativeGooglePlus(MainActivity.this);

Or, for an Engage-only integration:

engage.signOutNativeGooglePlus(MainActivity.this);

Revoking the Access Token and Disconnecting the App

To revoke the access token and disconnect the app from a user’s Google+ account, call:

Jump.revokeAndDisconnectNativeGooglePlus(MainActivity.this);

Or, for an Engage-only integration:

engage.revokeAndDisconnectNativeGooglePlus(MainActivity.this);

JUMP for Android Upgrade Guide

This guide describes how to upgrade from different versions of the library.

Generalized Upgrade Process

  1. Remove the Jump or JREngage module(s) from your project.
  2. Follow the steps in the JUMP for Android Integration Guide.

Note: Be sure to update your AndroidManifest.xml file.

Generalized Solutions

java: package com.janrain.android.engage.R does not exist
  • Use R instead.
java: package com.janrain.android.engage.utils does not exist
  • Use com.janrain.android.utils instead.
java: method createConnection in class com.janrain.android.engage.net.JRConnectionManager cannot be applied to given types;

required: java.lang.String,com.janrain.android.engage.net.JRConnectionManagerDelegate,java.lang.Object,java.util.List<org.apache.http.NameValuePair>,byte[],boolean

found: java.lang.String,<anonymous com.janrain.android.engage.net.JRConnectionManagerDelegate.SimpleJRConnectionManagerDelegate>,<nulltype>

reason: actual and formal argument lists differ in length
  • The signature of createConnection has changed to createConnection(String requestUrl, JRConnectionManagerDelegate delegate, Object tag, List<NameValuePair> requestHeaders, byte[] postData, boolean followRedirects).
  • requestHeaders and postData are both optional (can be null).
java: cannot find symbol
  symbol:   method logd(java.lang.String,java.lang.String)
  location: class com.janrain.android.engage.JREngage
  • Use com.janrain.android.utils.LogUtils instead.

Upgrading to v6.0.0

  • Important: This is the last release of this form of the Janrain Android Mobile libraries. Other than major bug fixes or compatibility updates, no further implementations will be released. A new Android sample application will be written using more modern Android tools and libraries.
  • Android Studio IDE is the only IDE that this release supports and has been tested with.
  • The Android Mobile libraries have removed all inter-dependencies on the Google, Facebook, and Twitter SDKs and libraries. The SimpleDemoNative app was created to demonstrate how to integrate native provider logon for these providers using their SDKs and libraries. Refer to the Android Native Authentication Guide for more information.
  • Note: Google Play/Sign-on libraries newer than version 8.1 are NOT supported. Google has changed the oAuth access token provisioning as of version 8.3 and it is no longer compatible with Janrain’s APIs at the time of this release. Janrain will be updating their APIs to support Google’s re-architecture in the future.
  • Resolved an issue with the CaptureJsonUtils.java file where customers with large amounts of user records would overflow the Integer data type.
  • If you want to use the Janrain Mobile libraries and sample code with the latest Android API levels, there are now dependencies on the deprecated org.apache.http.legacy.jar file. This file is included in the Github repo in the libs folder. Additional information on this can be found in the build.gradle file.

Upgrading to v5.0.1

The Janrain Mobile libraries and sample code now have dependencies on OKHttp. Follow the steps in the Eclipse Import Guide to add the necessary jars to your project.

Solutions when Upgrading to v4.7.0

When linking accounts, my implementation of `jrAuthenticationDidSucceedForLinkAccount` is never called.
  • jrAuthenticationDidSucceedForLinkAccount was moved from the JREngageDelegate to the Jump.CaptureLinkAccountHandler to prevent Social Sign-in-only applications from having to implement unnecessary methods. To fix this, add Jump.CaptureLinkAccountHandler to the list of interfaces that your delegate implements. For example: private class MyEngageDelegate implements JREngageDelegate, Jump.CaptureLinkAccountHandler {

Upgrading v2.0.1-v3.1.0 to v4.2.0

  1. Remove the JREngage module from your project.
  2. Follow the steps in the Android Engage-only Integration Guide (v2.0.1 through v3.1.0 did not support Capture).

Note: Be sure to update your AndroidManifest.xml file.

Solutions for Upgrading from v2.0.1-v2.0.12

java: package com.janrain.android.engage.utils does not exist
  • Import com.janrain.android.utils.PrefUtils and change references from Prefs to PrefUtils.
java: reference to showAuthenticationDialog is ambiguous, both method showAuthenticationDialog(android.app.Activity,java.lang.String) in com.janrain.android.engage.JREngage and method showAuthenticationDialog(java.lang.Boolean,java.lang.String) in com.janrain.android.engage.JREngage match
  • showAuthenticationDialg(Boolean, String) has been deprecated, use showAuthenticationDialog(Activity, String) instead and pass in the activity that is launching the authentication as the activity.

  • For example, in the old version of SimpleDemo we had mEngage.showAuthenticationDialog(null, "facebook") in MainActivity’s onCreate. To upgrade, we replaced it with mEngage.showAuthenticationDialog(MainActivity.this, "facebook").

Solutions for Upgrading from v3.0.0-v3.1.0

java: cannot find symbol
  symbol:   class JRCustomUiConfiguration
  location: package com.janrain.android.engage.ui
  • Use com.janrain.android.engage.ui.JRCustomInterfaceConfiguration instead.
java: cannot find symbol
  symbol:   class JRCustomUiView
  location: package com.janrain.android.engage.ui
  • Use com.janrain.android.engage.ui.JRCustomInterfaceView instead.
java: cannot find symbol
  symbol:   method showBetaDirectShareDialog(com.janrain.android.simpledemo.MainActivity,com.janrain.android.engage.types.JRActivityObject)
  location: variable mEngage of type com.janrain.android.engage.JREngage
  • showBetaDirectShareDialog has been removed.
java: method does not override or implement a method from a supertype** in reference to a subclass of SimpleJRConnectionManagerDelegate
  • The signature of connectionDidFail has changed to: connectionDidFail(Exception ex,HttpResponseHeaders responseHeaders, byte[] payload, String requestUrl, Object tag)

JUMP for Android User Registration Guide

This guide describes how to use the user registration feature in the JUMP Mobile libraries and sample code. This guide is a follow-on to the Jump for Android Integration Guide, which describes the fundamentals of the integration process.

Registration Types

There are three types of user registration:

  • Traditional registration–Registration as traditionally implemented. The user fills out a form and the fields of the form are submitted via a JUMP platform API, which registers the user.
  • Thin social registration–Automatic registration based on social identities. It is used only in the context of an authentication with a social identity. No form is presented to the user. The user’s social identity is used to populate the fields of a new user record if one does not already exist for their social identity identifier URL.
  • Two-step social registration–A registration form with pre-populated values from the user’s social identity. The first step is “the user authenticates with a social identity, but no user record is found, so a pre-populated form is returned to the user”. The second step is “the user submits the registration form”.

Traditional Registration

To perform traditional registration, first instantiate a new JSONObject:

JSONObject newUser = new JSONObject();

Then, present a registration form of your own creation to the user and allow them to fill in values. There should be a field in your form for each of the fields in your traditional registration form in your flow. (You can look in your flow directly, or ask your deployment engineer for a list of these fields.)

For example, for the default Capture schema and the standard user registration flow, display five text fields (one each) for the following attributes in the default Capture schema:

  • /email
  • /displayName
  • /firstName
  • /lastName
  • /password

When the user submits the form, copy the text field values into corresponding attributes in newUser. Once the user object is populated with values, call com.janrain.android.Jump#registerNewUser. Use null for the social registration token.

Upon completion, a method is invoked on your com.janrain.android.Jump.SignInResultHandler. onSuccess() is invoked for successful registrations and onFailure(SignInError) is invoked for failures. Form validation failures are communicated to your application as failures.

Handling Form Validation Failures

Capture performs server-side form validation on all forms. If there is a validation error, your result handler receives a failure method invocation. The error received in that method can be inspected, and form validation errors can be differentiated from other (for example, networking) errors and presented to the user.

To detect a form validation error, use com.janrain.android.capture.CaptureApiError#isFormValidationError. A validation error, once detected, can be further inspected by calling com.janrain.android.capture.CaptureApiError.getLocalizedValidationErrorMessages. This method returns a map of form field names to lists of localized error messages for that field. For example, it might return a map like:

{
    "displayName": ["Display name is required."],
    "email": ["Email address is not formatted correctly."],
    "password": ["Password is required."]
}

The localized validation failure messages will be localized in accordance with the locale used to configure the JUMP library and with the translations defined in your flow.

Thin Registration

Thin registration is enabled or disabled at the time that you configure the Capture library, via the captureEnableThinRegistration field in the JumpConfig instance used to initialize the JUMP library. Set to true to enable thin registration. No further configuration is required. When thin registration is possible, it will be performed by Capture automatically and the user will be signed in simultaneously.

Thin Registration Requirements

For thin registration to succeed, all Capture schema constraints and rules must be fulfillable with the social profile (see /entityType.setAttributeConstraints and /entityType.rules). If a constraint or rule cannot be met, thin registration will not occur and the JUMP library will return an instance of com.janrain.android.Jump.SignInResultHandler.SignInError#SignInError with an included com.janrain.android.capture.CaptureApiError which will have an error code of 310, (== com.janrain.android.capture.CaptureApiError#RECORD_NOT_FOUND). For example, if there is the schema constraint of ['required'] on the /email attribute of your schema, users attempting to sign in with Twitter (which does not profile an email address in its social profiles) will not be able to thin-register.

Two-step Social Registration

Two-step social registration is the composition of a failed social sign-in and a registration. It is first started via the social sign-in API, with a follow-on call to the registration API after the sign-in fails.

To perform a social registration, first the user is run through the social sign-in API. Inspect the error received in SignInResultHandler#onFailure(SignInError error) with error.captureApiError.isTwoStepRegFlowError().. If true, the sign-in error can be recovered by performing a social registration. The error received will also provide a pre-populated user object which should be used to pre-populate the social registration form.

Two-step Implementation

Two-step social registration is performed similarly to traditional registration (as described above) but with the addition of a social registration token in the call to com.janrain.android.Jump#registerNewUser.

The social registration token is retrieved from the sign-in error received in your SignInResultHandler#onFailure method, with the CaptureApiError#getSocialRegistrationToken method, and the pre-populated user object can be retrieved with CaptureApiError#getPreregistrationRecord.

With the pre-populated user record display a form with fields pre-populated by the properties of the pre-registration record, and pass the social registration token in with the registration message.

Social registration form validation errors are handled in the same way as traditional registration form validation errors.

Forgotten Passwords

When a user submits an incorrect email address or password in a traditional registration sign-in form, the user is given the option to create a new password. The AlertDialog that informs the user of the failed sign-in has a button to begin the forgotten password flow. Once the user clicks Forgot Password, another AlertDialog is displayed, asking the user to confirm their email address. If the user clicks Send, an API call is made to Capture that triggers an email containing instructions on how the user can reset their password.

To trigger the forgotten password flow directly, call:

Capture.performForgotPassword(emailAddress, new Capture.ForgotPasswordResultHandler() {..});

Example

In SimpleDemo, see the MainActivity for an example of the SignInResultHandler, and see RegistrationActivity for an example of a registration form (used for both traditional and social registration).