7

I am using LinkedIn in my iOS app. I want to save the access token for the future use.

The token is of non property type which cannot be saved in NSUserDefaults directly. I tried using NSKeyedArchiver for this but I got the output:

Token===oauth_token "(null)" oauth_token_secret "(null)" oauth_verifier "(null)"

The text in the token is coming but the values are coming null.

Code snippet 1 :

-(void)saveData :(LOAToken *)token
{
    NSFileManager *filemgr;
    NSString *docsDir;
    NSArray *dirPaths;

    filemgr = [NSFileManager defaultManager];

    // Get the documents directory
    dirPaths = NSSearchPathForDirectoriesInDomains(
                                                   NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = [dirPaths objectAtIndex:0];

    // Build the path to the data file
    NSString *dataFilePath = [[NSString alloc] initWithString: [docsDir
                                                                stringByAppendingPathComponent: @"data.archive"]];

    [NSKeyedArchiver archiveRootObject:
     token toFile:dataFilePath];
}


-(LOAToken *)GetToken
{
    NSFileManager *filemgr;
    NSString *docsDir;
    NSArray *dirPaths;

    filemgr = [NSFileManager defaultManager];

    // Get the documents directory
    dirPaths = NSSearchPathForDirectoriesInDomains(
                                                   NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = [dirPaths objectAtIndex:0];

    // Build the path to the data file
    NSString *dataFilePath = [[NSString alloc] initWithString: [docsDir
                                                                stringByAppendingPathComponent: @"data.archive"]];

    // Check if the file already exists
    if ([filemgr fileExistsAtPath: dataFilePath])
    {
        LOAToken *token;

        token = [NSKeyedUnarchiver
                     unarchiveObjectWithFile: dataFilePath];

        return token;
    }

    return NULL;
}

I also tried to save like this but the result is same:

Token===oauth_token "(null)" oauth_token_secret "(null)" oauth_verifier "(null)"

Code snippet 2 :

NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.accessToken];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:myEncodedObject forKey:@"myEncodedObjectKey"];
    [defaults synchronize];

   NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
   NSData *myEncodedObject = [defaults objectForKey:@"myEncodedObjectKey"];
            LOAToken *obj = (LOAToken *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];

Is there anything wrong with my coding or Access Token need some special technique to save?Please Suggest.

Piyush Dubey
  • 2,416
  • 1
  • 24
  • 39
Imran
  • 1,715
  • 2
  • 20
  • 42
  • You can save access token directly into user defaults.No need archive it – Pratyusha Terli Sep 05 '13 at 12:27
  • Thanks for the response.When I save to defaults directly I get message [NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '' of class 'OAToken'. Note that dictionaries and arrays in property lists must also contain only property values. – Imran Sep 05 '13 at 12:30
  • dont save OAToken object directly save the response body as i did and when you want to use access token initilaize it using reponseBody thi sway and use access token 'self.accessToken = [[NSUserDefaults standardUserDefaults] valueForKeyPath:@"accessToken"]; [[OAToken alloc] initWithHTTPResponseBody:self.accessToken]' – Pratyusha Terli Sep 05 '13 at 12:32
  • are u using oAuth 2.0 ? – keen Sep 05 '13 at 12:50
  • OAuth 1.0.Do you have any sample of OAuth 2.0? – Imran Sep 05 '13 at 13:42
  • HI Prat, Really is very helpful to me. I am also done all these action to save access token but i did not get solution. You did very logically. Thanks – arunit21 Oct 09 '13 at 04:42
  • hey @Imran i have migrated to OAuth 2.0 now. – Pratyusha Terli Jan 01 '15 at 07:54
  • @arunit21 Thank you :) – Pratyusha Terli Jul 21 '16 at 11:05

1 Answers1

10

this is how I saved. It worked for me.Hope it helps

- (void)accessTokenResult:(OAServiceTicket *)ticket didFinish:(NSData *)data
{
    NSDictionary *dict;
    NSString *responseBody = [[NSString alloc] initWithData:data
                                               encoding:NSUTF8StringEncoding];
    BOOL problem = ([responseBody rangeOfString:@"oauth_problem"].location != NSNotFound);
   if (problem)
   {
        DLog(@"Request access token failed.");
        DLog(@"%@",responseBody);
        dict = [NSDictionary dictionaryWithObjectsAndKeys:@"0",@"success",@"Request access token failed.",@"reason", nil];
   }
   else
   {
       self.accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
       [[NSUserDefaults standardUserDefaults] setObject:responseBody forKey:@"accessToken"];//save here
       [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"TokenRefreshDate"];//save here
       [[NSUserDefaults standardUserDefaults] synchronize];
       dict = [NSDictionary dictionaryWithObjectsAndKeys:@"1",@"success",@"Login Successful",@"reason", nil];
   }
   // Notify parent and close this view
   [[NSNotificationCenter defaultCenter] postNotificationName:@"loginViewDidFinish" object:self userInfo:dict];
   [self dismissViewControllerAnimated:YES completion:^{

   }];
 }

use saved responseBody in this way

self.accessToken = [[NSUserDefaults standardUserDefaults] valueForKeyPath:@"accessToken"];
NSURL *url = [NSURL URLWithString:@"http://api.linkedin.com/v1/people/~/connections:(id,first-name,last-name,headline,maiden-name,picture-url,formatted-name,location,positions,public-profile-url,specialties,num-connections,industry)"];

OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
                                                                   consumer:self.consumer
                                                                      token:[[OAToken alloc] initWithHTTPResponseBody:self.accessToken]
                                                                   callback:nil
                                                          signatureProvider:nil];

[request setValue:@"json" forHTTPHeaderField:@"x-li-format"];
OADataFetcher *fetcher = [[OADataFetcher alloc] init];
[fetcher fetchDataWithRequest:request
                         delegate:self
                didFinishSelector:@selector(connectionsApiCallResult:didFinish:)
                  didFailSelector:@selector(connectionsApiCallResult:didFail:) withId:0];

I hope I am clear this time

Pratyusha Terli
  • 2,343
  • 19
  • 31
  • Thanks for the answer.Next time when we enter the app Will it give access token on calling: self.accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody]; as we are saving response body(string). – Imran Sep 05 '13 at 12:38
  • from next time onwards you should take responseBody string from NSUserDa]efaults and then create OAToken object.responseBody will be stored will be available until you uninstall your app – Pratyusha Terli Sep 05 '13 at 12:42
  • Let me clarify as name accessToken Conflicts. `self.accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];` in this line accessToken is instance of OAToken and `self.accessToken = [[NSUserDefaults standardUserDefaults] valueForKeyPath:@"accessToken"];` in this line accessToken is NSString. – Pratyusha Terli Sep 05 '13 at 12:44
  • I think I made hurry.I already have the access token then why we are making request OAMutableURLRequest again. – Imran Sep 05 '13 at 13:40
  • Do we need to follow all the procedure to get the access token like the first time when login dialog appears and use the access token for the request.Some more hint. – Imran Sep 05 '13 at 13:45
  • You dont need to take accessToken by logging in user again as you have the response body.Whatever calls you have to make to api like getting connections list of user.you can do using the responseBody you have stored in user defaults.see my updated answer – Pratyusha Terli Sep 06 '13 at 04:11
  • Working like a charm.Thanks a lot.One more question.I have implemented OAuth 1.0. Have you implemented OAuth 2.0.If yes then can you please suggest me the necessary changes that I have to make to in this code. – Imran Sep 06 '13 at 05:33
  • I have not implemented it using OAuth 2.0 but you can refer to this link http://developer.linkedin.com/documents/authentication this provides the procedure for migrating from 1.0 to 2.0 – Pratyusha Terli Sep 06 '13 at 05:43
  • @PratyushaTerli Thanks for your code ,i need to save the user token in parse.com so do we need to save response body – – SreeHarsha Sep 10 '13 at 08:49
  • I think you will need access token anyway whether you use parse.com or not and that you can get only by saving the responseBody. – Imran Sep 10 '13 at 08:59
  • @SreeHarsha I am sorry but I do not have any idea about parse.com . I am saving responseBody in NSUserDefaults as OAToken object (accessToken) cannot be directly saved into user defaults – Pratyusha Terli Sep 11 '13 at 05:04
  • When I go on with the above code I get the below error, does anyone have any idea? Please let me know. auth_problem=signature_invalid&oauth_problem_advice=com.linkedin.security.auth.pub.LoginDeniedInvalidAuthTokenException – arunit21 Oct 04 '13 at 13:02
  • Hello @PratyushaTerli, How can I clear cache for LinkedIn like we clear for twitter and Facebook ? – Sushil Sharma Jun 06 '15 at 07:14
  • You can clear accessToken saved in user defaults to clear cache. – Pratyusha Terli Jul 21 '16 at 11:02