Permalink
Browse files

Added the extendAccessToken method to facebook-ios-sdk

Summary:
Whenever user makes an API call the SDK checks if the access token is about to
expire.  If that's the case SDK will try to silently refresh the token.
Developer can also force the refreshing process by calling [facebook
extendAccessToken] method (this might be useful for apps that doesn't make
frequent API calls). Also provided an example of this functionality in the
Hackbook.

Test Plan:
With prod: tried refreshing the token and check if the expirationDate is
correct.

With sandbox:
 - disabling checking the ssl certificates in the sdk (done by following lines
(src/FBRequest.m) - I'm sure there's an easier way, but I don't know it :P):

  LANG=C
  - (BOOL)connection:(NSURLConnection *)connection
canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return [protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust];
  }
  - (void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust])
      [challenge.sender useCredential:[NSURLCredential
credentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
    [challenge.sender
continueWithoutCredentialForAuthenticationChallenge:challenge];
  }

- changing the rest server url (in my case:)

  LANG=C
  static NSString* kRestserverBaseURL =
@"https://api.kamil.devrs332.facebook.com/method/";

- after that I switched to app which access expires after 10 minutes and tested
if the refreshing process behaves correctly (had to modify isSessionOld
function)

Reviewers: yariv, jimbru, brent, ekoneil

Reviewed By: yariv

CC: lshepard, ekoneil, jgabbard, brent, yariv, kamil, trvish

Differential Revision: https://phabricator.fb.com/D371702

Task ID: 823099
  • Loading branch information...
1 parent 6e15f95 commit 4969a9928e5182eefa347158e4491dc46dfc9a37 Kamil Kraszewski committed with Kamil Kraszewski Dec 19, 2011
@@ -19,7 +19,6 @@
@interface APIResultsViewController : UIViewController
<FBRequestDelegate,
-FBSessionDelegate,
UITableViewDataSource,
UITableViewDelegate>{
NSMutableArray *myData;
@@ -43,37 +43,44 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[navController.navigationBar setTintColor:[UIColor colorWithRed:0/255.0
green:51.0/255.0
- blue:102.0/255.0
+ blue:102.0/255.0
alpha:1.0]];
[navController.navigationBar setBarStyle:UIBarStyleBlackTranslucent];
self.navigationController = navController;
[rootViewController release];
[navController release];
-
+
// Initialize Facebook
facebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:rootViewController];
-
+
+ // Check and retrieve authorization information
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
+ facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
+ facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
+ }
+
// Initialize API data (for views, etc.)
apiData = [[DataSet alloc] init];
-
+
// Initialize user permissions
userPermissions = [[NSMutableDictionary alloc] initWithCapacity:1];
-
+
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
-
+
// Check App ID:
// This is really a warning for the developer, this should not
// happen in a completed app
if (!kAppId) {
- UIAlertView *alertView = [[UIAlertView alloc]
- initWithTitle:@"Setup Error"
- message:@"Missing app ID. You cannot run the app until you provide this in the code."
- delegate:self
- cancelButtonTitle:@"OK"
- otherButtonTitles:nil,
+ UIAlertView *alertView = [[UIAlertView alloc]
+ initWithTitle:@"Setup Error"
+ message:@"Missing app ID. You cannot run the app until you provide this in the code."
+ delegate:self
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil,
nil];
[alertView show];
[alertView release];
@@ -83,15 +90,15 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
NSString *url = [NSString stringWithFormat:@"fb%@://authorize",kAppId];
BOOL bSchemeInPlist = NO; // find out if the sceme is in the plist file.
NSArray* aBundleURLTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
- if ([aBundleURLTypes isKindOfClass:[NSArray class]] &&
+ if ([aBundleURLTypes isKindOfClass:[NSArray class]] &&
([aBundleURLTypes count] > 0)) {
NSDictionary* aBundleURLTypes0 = [aBundleURLTypes objectAtIndex:0];
if ([aBundleURLTypes0 isKindOfClass:[NSDictionary class]]) {
NSArray* aBundleURLSchemes = [aBundleURLTypes0 objectForKey:@"CFBundleURLSchemes"];
if ([aBundleURLSchemes isKindOfClass:[NSArray class]] &&
([aBundleURLSchemes count] > 0)) {
NSString *scheme = [aBundleURLSchemes objectAtIndex:0];
- if ([scheme isKindOfClass:[NSString class]] &&
+ if ([scheme isKindOfClass:[NSString class]] &&
[url hasPrefix:scheme]) {
bSchemeInPlist = YES;
}
@@ -101,21 +108,29 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
// Check if the authorization callback will work
BOOL bCanOpenUrl = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString: url]];
if (!bSchemeInPlist || !bCanOpenUrl) {
- UIAlertView *alertView = [[UIAlertView alloc]
- initWithTitle:@"Setup Error"
- message:@"Invalid or missing URL scheme. You cannot run the app until you set up a valid URL scheme in your .plist."
- delegate:self
- cancelButtonTitle:@"OK"
- otherButtonTitles:nil,
+ UIAlertView *alertView = [[UIAlertView alloc]
+ initWithTitle:@"Setup Error"
+ message:@"Invalid or missing URL scheme. You cannot run the app until you set up a valid URL scheme in your .plist."
+ delegate:self
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil,
nil];
[alertView show];
[alertView release];
}
}
-
+
return YES;
}
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+ // Although the SDK attempts to refresh its access tokens when it makes API calls,
+ // it's a good practice to refresh the access token also when the app becomes active.
+ // This gives apps that seldom make api calls a higher chance of having a non expired
+ // access token.
+ [[self facebook] extendAccessTokenIfNeeded];
+}
+
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [self.facebook handleOpenURL:url];
}
@@ -103,7 +103,7 @@ - (void)showLoggedOut {
nameLabel.text = @"";
// Get the profile image
[profilePhotoImageView setImage:nil];
-
+
[[self navigationController] popToRootViewControllerAnimated:YES];
}
@@ -245,19 +245,11 @@ - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
HackbookAppDelegate *delegate = (HackbookAppDelegate *)[[UIApplication sharedApplication] delegate];
- // Check and retrieve authorization information
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- if ([defaults objectForKey:@"FBAccessTokenKey"]
- && [defaults objectForKey:@"FBExpirationDateKey"]) {
- [delegate facebook].accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
- [delegate facebook].expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
- }
if (![[delegate facebook] isSessionValid]) {
[self showLoggedOut];
} else {
[self showLoggedIn];
}
-
}
- (void)viewWillDisappear:(BOOL)animated {
@@ -315,6 +307,13 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}
+- (void)storeAuthData:(NSString *)accessToken expiresAt:(NSDate *)expiresAt {
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:accessToken forKey:@"FBAccessTokenKey"];
+ [defaults setObject:expiresAt forKey:@"FBExpirationDateKey"];
+ [defaults synchronize];
+}
+
#pragma mark - FBSessionDelegate Methods
/**
* Called when the user has logged in successfully.
@@ -323,16 +322,16 @@ - (void)fbDidLogin {
[self showLoggedIn];
HackbookAppDelegate *delegate = (HackbookAppDelegate *)[[UIApplication sharedApplication] delegate];
+ [self storeAuthData:[[delegate facebook] accessToken] expiresAt:[[delegate facebook] expirationDate]];
- // Save authorization information
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- [defaults setObject:[[delegate facebook] accessToken] forKey:@"FBAccessTokenKey"];
- [defaults setObject:[[delegate facebook] expirationDate] forKey:@"FBExpirationDateKey"];
- [defaults synchronize];
-
[pendingApiCallsController userDidGrantPermission];
}
+-(void)fbDidExtendToken:(NSString *)accessToken expiresAt:(NSDate *)expiresAt {
+ NSLog(@"token extended");
+ [self storeAuthData:accessToken expiresAt:expiresAt];
+}
+
/**
* Called when the user canceled the authorization dialog.
*/
@@ -359,13 +358,13 @@ - (void)fbDidLogout {
/**
* Called when the session has expired.
*/
-- (void)fbSessionInvalidated {
+- (void)fbSessionInvalidated {
UIAlertView *alertView = [[UIAlertView alloc]
- initWithTitle:@"Auth Exception"
- message:@"Your session has expired."
- delegate:nil
- cancelButtonTitle:@"OK"
- otherButtonTitles:nil,
+ initWithTitle:@"Auth Exception"
+ message:@"Your session has expired."
+ delegate:nil
+ cancelButtonTitle:@"OK"
+ otherButtonTitles:nil,
nil];
[alertView show];
[alertView release];
View
@@ -25,7 +25,7 @@
* and Graph APIs, and start user interface interactions (such as
* pop-ups promoting for credentials, permissions, stream posts, etc.)
*/
-@interface Facebook : NSObject<FBLoginDialogDelegate>{
+@interface Facebook : NSObject<FBLoginDialogDelegate,FBRequestDelegate>{
NSString* _accessToken;
NSDate* _expirationDate;
id<FBSessionDelegate> _sessionDelegate;
@@ -35,6 +35,8 @@
NSString* _appId;
NSString* _urlSchemeSuffix;
NSArray* _permissions;
+ BOOL _isExtendingAccessToken;
+ NSDate* _lastAccessTokenUpdate;
}
@property(nonatomic, copy) NSString* accessToken;
@@ -51,6 +53,12 @@
- (void)authorize:(NSArray *)permissions;
+- (void)extendAccessToken;
+
+- (void)extendAccessTokenIfNeeded;
+
+- (BOOL)shouldExtendAccessToken;
+
- (BOOL)handleOpenURL:(NSURL *)url;
- (void)logout;
@@ -93,8 +101,6 @@
*/
@protocol FBSessionDelegate <NSObject>
-@optional
-
/**
* Called when the user successfully logged in.
*/
@@ -106,13 +112,23 @@
- (void)fbDidNotLogin:(BOOL)cancelled;
/**
+ * Called after the access token was extended. If your application has any
+ * references to the previous access token (for example, if your application
+ * stores the previous access token in persistent storage), your application
+ * should overwrite the old access token with the new one in this method.
+ * See extendAccessToken for more details.
+ */
+- (void)fbDidExtendToken:(NSString*)accessToken
+ expiresAt:(NSDate*)expiresAt;
+
+/**
* Called when the user logged out.
*/
- (void)fbDidLogout;
/**
* Called when the current session has expired. This might happen when:
- * - the access token expired
+ * - the access token expired
* - the app has been disabled
* - the user revoked the app's permissions
* - the user changed his or her password
Oops, something went wrong.

0 comments on commit 4969a99

Please sign in to comment.