Skip to content

Authentication basics

joeldev edited this page Mar 15, 2013 · 2 revisions

Setting a saved access token

[ANKClient sharedClient].accessToken = theAccessToken;

You should call this if the user has already authorized the application and you have an access token to use. Authentication only needs to be done when the token is no longer valid or the user has never authorized the app before (or if the token expires).

Since each accessToken maps to a single authorized user, you will need to use a slightly different approach if you plan to support multiple user accounts.

I recommend using something like SSKeychain to store the access token. If you are using username/password authentication, do not store the user's password in any way. ONLY the access token itself should be stored.

Username/Password Authentication

App.net recommends that any app being submitted to the Mac or iOS App Store use username/password authentication instead of OAuth (source, see "Registering your app"). You can find out more about Password Authentication and how to apply for it here.

Once you have been approved for username/password auth, getting authenticated with ADNKit is a single method call:

/* this assumes you have two text fields, usernameField and passwordField */

// ask for permission to see user information and send new Posts
ANKAuthScope requestedScopes = ANKAuthScopeBasic | ANKAuthScopeWritePost;

// handler to call when finished authenticating
id handler = ^(BOOL success, NSError *error) {
	if (success) {
		NSLog(@"we are authenticated and ready to make API calls!");
	} else {
		NSLog(@"could not authenticate, error: %@", error);
	}
};

// authenticate, calling the handler block when complete
[[ANKClient sharedClient] authenticateUsername:usernameField.text
				      password:passwordField.text
				      clientID:@"xxxxxx"
			   passwordGrantSecret:@"zzzzzz"
				    authScopes:requestedScopes
			     completionHandler:handler];

Once the completion block is called with a successful response, you are completely good to go and can start using the rest of the API calls. You don't even need to set the accessToken on the shared ANKClient, that happens automatically.

OAuth Authentication

While not being the preferred approach for native applications, ADNKit will also help you out with web OAuth authentication (more info) if that's the route you choose to take (it's sometimes faster to start with because it doesn't require explicit approval like username/password auth does).

For the redirectURI, you should use a URL scheme that your app is registered to handle (Apple documentation).

Using the method below, you can generate an NSURLRequest that can be loaded in a webview to provide the user with a way to auth.

// ask for permission to see user information, fetch their streams, and send Posts
ANKAuthScope requestedScopes = ANKAuthScopeBasic | ANKAuthScopeStream | ANKAuthScopeWritePost;

// set the completion block to use when the whole process is completed (despite spanning multiple requests, this is the block where we handle completion of oauth authentication)
[ANKClient sharedClient].webAuthCompletionHandler = ^(BOOL success, NSError *error) {
	if (success) {
		NSLog(@"we are authenticated and ready to make API calls!");
	} else {
		NSLog(@"could not authenticate, error: %@", error);
	}
};

// create a URLRequest to kick off the auth process...
NSURLRequest *request = [[ANKClient sharedClient] webAuthRequestForClientID:@"xxxxxx"
								redirectURI:@"myapp://auth"
								 authScopes:requestedScopes
								      state:nil
							  appStoreCompliant:YES];
// ...and load it to start things off
[myWebView loadRequest:request];

Once the user authorizes the application, your redirectURI will get called and passed an auth code (in the format of yourURI/?code=CODE). Using something like JLRoutes to register a route from within applicationDidFinishLaunching makes this very easy:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // ...
  [JLRoutes addRoute:@"/auth" handler:^BOOL(NSDictionary *parameters) {
    NSString *accessCode = parameters["code"];
    
	// now that we have the accessCode, we need to finish the process.
	[[ANKClient sharedClient] authenticateWebAuthAccessCode:accessCode forClientID:@"xxxxxx" clientSecret:@"ssssss"];

    return YES; // return YES to say we have handled the route
  }];
  // ...
  return YES;
}

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

This can be done without JLRoutes, and all you need to do is parse the code out from the URL. I recommend grabbing the query string from [URL query] and extracting the substring after "code=".

Once your original web auth completion block is called (which was set up in the previous block of code), you are ready to go. No need to set the accessToken, that is handled automatically.