MFAuthLib for iOS

NetIQ AccessManager Mobile SDK for iOS

NetIQ Mobile SDK [MFAuthLib] for iOS is a client SDK for communicating with NetIQ Access Manager OAuth 2.0 and OpenID Connect providers. It is based on the OpenID AppAuth library and is contained within it.
In addition to mapping the raw protocol flows, convenience methods are available to assist with common tasks like performing an action with fresh tokens.

It follows the best practices set out in OAuth 2.0 for Native Apps including using SFSafariViewController on iOS for the auth request. So, the UIWebView is explicitly not supported due to usability and security reasons.

It also supports the PKCE extension to OAuth which was created to secure authorization codes in public clients when custom URI scheme redirects are used. The library is friendly to other extensions (standard or otherwise) with the ability to handle additional params in all protocol requests and responses.

Specification

iOS

Supported Versions

MFAuthLib supports iOS 9 and above.

iOS 9+ uses the in-app browser tab pattern (via SFSafariViewController), and falls back to the system browser (mobile Safari) on earlier versions.

Authorization Server Requirements

Both Custom URI Schemes (all supported versions of iOS) and Universal Links (iOS 9+) can be used with the library.

In general, MFAuthLib can work with any Authorization Server (AS) that supports native apps, either through custom URI scheme redirects, or universal links.
AS’s that assume all clients are web-based or require clients to maintain confidentiality of the client secrets may not work well.

Setup

Framework Library

You can use MFAuthLib as a Framework library.
iOS Framework is a collection of resources; it collects a static library and its header files into a single structure that Xcode can easily incorporate into your projects making it easier for the developer.
This requires linking the library into your project.
It is still, however, not shared across iOS app boundaries.

Suggested configuration:

  1. Create an XCode Workspace.
  2. Include MFAuthLib as a linked library for your target
    (in the “General -> Linked Framework and Libraries” section of your target). Make sure to check copy resources.
  3. Include MFAuthLib as embedded binary for your target (in the “General -> Embedded Binaries” section of your target).
    Note, this will also make an entry in Linked Frameworks and Libraries section. If it has duplicate entries, delete one.
  4. Additionally, you will need to add the contained AppAuth framework (from Frameworks folder in MFAuthLib.framework file) to the “Embedded Binaries” section.

Follow the instructions in the Sample Apps to configure with your own OAuth client.

Auth Flow

MFAuthLib employs the OAuth 2 Authorization Code Flow.

MFAuthService is the main class that keeps track of the authorization and token requests & responses, and provides a convenience method to call an API with fresh tokens.
It also securely stores the authentication tokens in the device Keychain to retain the authorization state of the session.

Configuration

You can configure MFAuthLib by specifying the endpoints directly:

NSURL *authorizationEndpoint =
    [NSURL URLWithString:@"https://idp.example.com/nidp/oauth/nam/authz"];
NSURL *tokenEndpoint =
    [NSURL URLWithString:@"https://idp.example.com/nidp/oauth/nam/token"];

MFServiceConfiguration *configuration =
    [[MFServiceConfiguration alloc]
        initWithAuthorizationEndpoint:authorizationEndpoint
                        tokenEndpoint:tokenEndpoint];

// perform the auth request...

Or through discovery :

NSURL *discoveryUrl = [NSURL URLWithString:@"https://idp.example.com/nidp/oauth/nam/.well-known/openid-configuration"];

// alternateively, you can also specify the issuer url
NSURL *issuer = [NSURL URLWithString:@"https://idp.example.com/nidp/oauth/nam"];

[MFAuthService discoverServiceConfigurationForIssuer:discoveryUrl completion:^(MFServiceConfiguration *_Nullable configuration, NSError *_Nullable error) {

  if (!configuration) {
    NSLog(@"Error retrieving discovery document: %@",
          [error localizedDescription]);
    return;
  }

  // perform the auth request...
}];

Authorizing – iOS

First you need to have a property in your AppDelegate to hold the session, in order to continue the authorization flow from the redirect.

// property of the app's AppDelegate
@property(nonatomic, strong, nullable)
    id<OIDAuthorizationFlowSession> currentAuthorizationFlow;

And your main class, a property to store the auth state:

// property of the containing class
@property(nonatomic, readonly, nullable) MFAuthService *authService;

Then, initiate the authorization request. By using the
signInWithClientId convenience method, the token exchange will be performed automatically, and everything will be protected with PKCE (if the server supports it). You will get the callback with a Success boolean flag or Error.

// build out the configuration parameters
...

// performs authentication request
AppDelegate *appDelegate =
    (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.currentAuthorizationFlow = [_authService  signInWithClientId:[accountConfig getClientId] 
    clientSecret:[accountConfig getClientSecret]
          scopes:arScopes
     redirectURL:[ NSURL URLWithString:[accountConfig getRedirectUri] ]
     presentingViewController:self
     withBlock:^(BOOL success, NSError * _Nullable error) {
                       if (success) {
                           [self logMessage:@"New Access Token Expiration: %@", [_authService getAccessTokenExpiryTimeString] ];
                           [self saveConfig:sProvider];
                       } else {
                           [self logMessage:@"Error during OAuth flow %@", [error localizedDescription]];
                       }
                       inflight = NO;
                       [self updateUI];
                   }];
}];

Handling the Redirect

The authorization response URL is returned to the app via the iOS openURL app delegate method, so you need to pipe this through to the current authorization session (created in the previous session).

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<NSString *, id> *)options {
  // Sends the URL to the current authorization flow (if any) which will 
  // process it if it relates to an authorization response.
  if ([_currentAuthorizationFlow resumeAuthorizationFlowWithURL:url]) {
    _currentAuthorizationFlow = nil;
    return YES;
  }

  // Your additional URL handling (if any) goes here.

  return NO;
}

Making API Calls

MFAuthLib gives you the raw token information, if you need it. However we recommend that users of the MFAuthService convenience wrapper use the provided performActionWithFreshTokens: method to perform their API calls to avoid needing to worry about token freshness.

[_authService performActionWithFreshToken:^(NSString *_Nonnull accessToken, NSString *_Nonnull idToken, NSError *_Nullable error) {
 
  if (error) {
    NSLog(@"Error fetching fresh tokens: %@", [error localizedDescription]);
    return;
  }

  // perform your API request using the tokens
}];

API Documentation

Browse the API documentation.

Included Samples

You can try out the iOS sample apps included in the distribution for e.g. by opening TApp2/TApp2.xcodeproj. Be sure to follow the instructions in TApp2/README.md to configure your own OAuth client ID for use with the example.