1

I have an iOS Application which authenticates with the Google Plus API via OAuth 2.0. The issue I have is that I can't POST my moment even though I have followed the Google Documentation exactly. Here is my POST request:

NSString *gp_moment = [NSString stringWithFormat:@"https://www.googleapis.com/plus/v1/people/me/moments/vault?access_token=%@", token_gplus];
        NSString *urlString = gp_moment;

        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
        [request setURL:[NSURL URLWithString:urlString]];
        [request setHTTPMethod:@"POST"];

        // Set the header - Content-Type.
        NSDictionary *the_header = @{@"Content-type" : @"application/json",
                                     @"userId" : @"me",
                                     @"collection" : @"vault",
                                     @"requestvisibleactions" : @"http://schemas.google.com/AddActivity"};

        [request setAllHTTPHeaderFields:the_header];

        // Set the metadata for the GP Moment (eg: name). -  request_visible_actions

        NSDictionary *metadata = @{@"target" : @{
                                           @"id" : @"replacewithuniqueidforaddtarget",
                                           @"image" : @"http://www.google.com/s2/static/images/GoogleyEyes.png",
                                           @"type": @"http://schema.org/CreativeWork",
                                           @"description" : @"test_desc",
                                           @"name" : @"TESTNAME",
                                           },
                                   @"type" : @"http://schemas.google.com/AddActivity"};

        // Convert metadata into JSON format and submit.
        NSError *jError = nil;
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:metadata options:NSJSONWritingPrettyPrinted error:&jError];
        [request setHTTPBody:jsonData];

        NSHTTPURLResponse *response = nil;
        NSError *error = nil;

        NSData *returnedData;
        returnedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        NSDictionary *headers = [response allHeaderFields];

        NSLog(@"DATA: %@", [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding]);
        NSLog(@"%@", headers);
        NSLog(@"%@", response);
        NSLog(@"%@", error);

UPDATE - HOW I AM GETTING THE OAUTH TOKEN

I am getting the token by using the GTMOAuth2 iOS library provided by Google. It has 4 main classes which I am using:

The GTMOAuth2 Library files

This is the code I have implemented from the classes into my ViewController:

-(GTMOAuth2Authentication *)begin_authorization {

// Set the token URL to the token endpoint.
NSURL *tokenURL;

// Set a bogus redirect URI. It won't actually be used as the redirect will
// be intercepted by the OAuth library and handled in the app.
NSString *redirectURI;

GTMOAuth2Authentication *auth;
tokenURL = [NSURL URLWithString:@"https://accounts.google.com/o/oauth2/token"];
redirectURI = @"http://localhost:3000/oauth/callback/";

    auth = [GTMOAuth2Authentication authenticationWithServiceProvider:@"GooglePlus" tokenURL:tokenURL redirectURI:redirectURI clientID:kMyClientID_gplus clientSecret:kMyClientSecret_gplus];
[auth setScope:@"https://www.googleapis.com/auth/plus.login"];

// Set the appropriate token type.
[auth setTokenType:@"Bearer"];

return auth;
}

-(void)authorize:(NSString *)service {
    GTMOAuth2Authentication *auth = [self begin_authorization];

// Prepare the Authorization URL. We will pass in the name of the service
// that we wish to authorize with.
NSURL *authURL;
authURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://accounts.google.com/o/oauth2/auth/"]];

NSString *keyname;
keyname = [NSString stringWithFormat:@"GooglePlus"];

// Display the authentication view
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth authorizationURL:authURL keychainItemName:keyname delegate:self finishedSelector:@selector(viewController:finishedWithAuth:error:)];

[viewController setBrowserCookiesURL:[NSURL URLWithString:@"https://accounts.google.com/o/oauth2/auth/"]];

// Push the authentication view to our navigation controller instance
[[self navigationController] pushViewController:viewController animated:YES];
}

-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error {

if (error != nil) {
    // Authentication failed
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Authorization Failed" message:[error localizedDescription] delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
    [alertView show];
}

else {
    // Authentication succeeded
    // Assign the access token to the instance property for later use

    account_check = auth.accessToken;
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:account_check forKey:@"gp_token"];
    [defaults synchronize];
}
}

In the GTMOAuth2SignIn.m file I am also setting the offline_access and "requestvisisbleactions" parameters like so:

NSMutableDictionary *paramsDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                 @"code", @"response_type",
                                 clientID, @"client_id",
                                 scope, @"scope", // scope may be nil
                                 @"force", @"approval_prompt",
                                 @"offline", @"access_type",
                                 @"http://schemas.google.com/AddActivity", @"requestvisibleactions",
                                 nil];

UPDATE - 2

I have tried looking through all the Google Plus documentation as well as looking through the differences between "requestvisisbleactions" and "request_visisble_actions" and still nothing works. Does anyone know what is wrong?

UPDATE - 3 - The error I am still getting

I keep on getting this error from Google Plus API. I just don't know why...:

{
"error": {
  "errors": [
   {
    "domain": "global",
    "reason": "unauthorized",
    "message": "Unauthorized"
   }
  ],
  "code": 401,
  "message": "Unauthorized"
 }
}
Supertecnoboff
  • 6,406
  • 11
  • 57
  • 98
  • 1
    What error is it reporting? – Prisoner Jun 05 '14 at 15:10
  • @Prisoner I am getting the error "401 not authorised". But the thing is, if the get rid of the JSON body or just edit it, I don't get this error anymore. And more to the point my access token is all setup correctly. – Supertecnoboff Jun 05 '14 at 16:26
  • @Prisoner Do you know what might be wrong? – Supertecnoboff Jun 06 '14 at 09:51
  • Can you update the question to include the code where you are requesting the access token? – Prisoner Jun 06 '14 at 12:40
  • @Prisoner For the time being I am using NSUserDefaults to store the access_token (just for testing) and I can tell you it all works perfectly. Every other GET and POST request I make to the Google server via OAuth 2 works perfectly. So the issue here is not the access token. – Supertecnoboff Jun 06 '14 at 14:33
  • @Prisoner On this SO answer, it says to add "request_visible_actions" parameter. How do I do this? (http://stackoverflow.com/a/15167718/1598906) – Supertecnoboff Jun 06 '14 at 14:35
  • 1
    It depends on how you are getting the auth token in the first place. the "request_visible_actions" is part of the OAuth request. If you edit your question to indicate how you got the auth token, I can assist you in how to set the visible actions for it. – Prisoner Jun 06 '14 at 15:19
  • @Prisoner Ok sir, I have updated my answer with how I am getting my access token. Thanks for your help :) – Supertecnoboff Jun 06 '14 at 16:09
  • Is there a reason you are not using the Google+ SDK ? – Lefteris Jun 10 '14 at 10:58
  • Also is scope set to "https://www.googleapis.com/auth/plus.login" in your paramsDict ? – Lefteris Jun 10 '14 at 13:15
  • @Lefteris Yes I am now using that scope and it is still not working. I am not using Google Plus SDK because it forces a orange popup for sharing which is annoying and doesn't fit in with my iOS app. – Supertecnoboff Jun 11 '14 at 11:59

1 Answers1

4

I believe that you need to use request_visible_actions. So your parameters might be set as

NSMutableDictionary *paramsDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @"code", @"response_type",
                                   clientID, @"client_id",
                                   scope, @"scope", // scope may be nil
                                   @"force", @"approval_prompt",
                                   @"offline", @"access_type",
                                   @"http://schemas.google.com/AddActivity", @"request_visible_actions",
                                   nil];
Prisoner
  • 49,922
  • 7
  • 53
  • 105
  • Just tried this and no unfortunately it still comes up with the unauthorised error :( Can you think of anything else that I may be doing wrong/have not done? – Supertecnoboff Jun 06 '14 at 17:12
  • Actually this did work in the end. There was something else I had to change as well. You sir will also be getting the bounty :) – Supertecnoboff Jun 15 '14 at 15:34
  • Thanks! For completeness, what else was necessary? – Prisoner Jun 15 '14 at 22:58
  • 1
    Oh my scope was wrong as well as not having the request_visible_actions parameter set. But now that I fixed the scope and used your solution, it works fine. – Supertecnoboff Jun 17 '14 at 09:28