Skip to content

Commit

Permalink
Added the extendAccessToken method to facebook-ios-sdk
Browse files Browse the repository at this point in the history
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
Kamil Kraszewski authored and Kamil Kraszewski committed Dec 22, 2011
1 parent 6e15f95 commit 4969a99
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 52 deletions.
1 change: 0 additions & 1 deletion sample/Hackbook/Hackbook/APIResultsViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

@interface APIResultsViewController : UIViewController
<FBRequestDelegate,
FBSessionDelegate,
UITableViewDataSource,
UITableViewDelegate>{
NSMutableArray *myData;
Expand Down
57 changes: 36 additions & 21 deletions sample/Hackbook/Hackbook/HackbookAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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;
}
Expand All @@ -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];
}
Expand Down
41 changes: 20 additions & 21 deletions sample/Hackbook/Hackbook/RootViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ - (void)showLoggedOut {
nameLabel.text = @"";
// Get the profile image
[profilePhotoImageView setImage:nil];

[[self navigationController] popToRootViewControllerAnimated:YES];
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand All @@ -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.
*/
Expand All @@ -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];
Expand Down
24 changes: 20 additions & 4 deletions src/Facebook.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,6 +35,8 @@
NSString* _appId;
NSString* _urlSchemeSuffix;
NSArray* _permissions;
BOOL _isExtendingAccessToken;
NSDate* _lastAccessTokenUpdate;
}

@property(nonatomic, copy) NSString* accessToken;
Expand All @@ -51,6 +53,12 @@

- (void)authorize:(NSArray *)permissions;

- (void)extendAccessToken;

- (void)extendAccessTokenIfNeeded;

- (BOOL)shouldExtendAccessToken;

- (BOOL)handleOpenURL:(NSURL *)url;

- (void)logout;
Expand Down Expand Up @@ -93,8 +101,6 @@
*/
@protocol FBSessionDelegate <NSObject>

@optional

/**
* Called when the user successfully logged in.
*/
Expand All @@ -105,14 +111,24 @@
*/
- (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
Expand Down

0 comments on commit 4969a99

Please sign in to comment.